如何确定 CSV 文件中的分隔符

2022-09-03 13:39:08

我有一个场景,我必须解析来自不同来源的CSV文件,解析代码非常简单明了。

        String csvFile = "/Users/csv/country.csv";
        String line = "";
        String cvsSplitBy = ",";
        try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
            while ((line = br.readLine()) != null) {
                // use comma as separator
                String[] country = line.split(cvsSplitBy);
                System.out.println("Country [code= " + country[4] + " , name=" + country[5] + "]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

我的问题来自CSV分隔符字符,我有很多不同的格式,有时它是一个有时它是一个,;

在解析文件之前,是否有任何方法可以确定分隔符字符


答案 1

单声道解析器支持自动检测分隔符(也包括行尾和引号)。只需使用它而不是与代码斗争:

CsvParserSettings settings = new CsvParserSettings();
settings.detectFormatAutomatically();

CsvParser parser = new CsvParser(settings);
List<String[]> rows = parser.parseAll(new File("/path/to/your.csv"));

// if you want to see what it detected
CsvFormat format = parser.getDetectedFormat();

免责声明:我是这个库的作者,我确保涵盖了各种角落案例。它是开源和免费的(Apache 2.0许可证)

希望这有帮助。


答案 2

是,但仅当不允许分隔符字符作为常规文本存在时

最简单的答案是有一个包含所有可用分隔符字符的列表,并尝试识别正在使用的字符。即使如此,您也必须对文件或创建它们的人/人施加一些限制。请看以下两种方案:

案例1 - 文件内容.csv

test,test2,test3

案例2 - 文件内容.csv

test1|test2,3|test4

如果您事先了解分隔符字符,则可以使用 拆分第一个字符串,并使用 拆分第二个字符串,得到相同的结果。但是,如果您尝试通过解析文件来标识分隔符,则可以使用该字符拆分两个字符串,最终将得到以下结果:,|,

情况 1 - 使用 进行拆分的结果

test1
test2
test3

情况 2 - 使用 拆分的结果

test1|test2
3|test4

由于缺乏对使用哪个分隔符字符的先验知识,您无法创建一种“神奇”的算法来解析文本的每个组合;即使是正则表达式或计算字符的出现次数也无法拯救您。

最坏情况

test1,2|test3,4|test5

通过查看文本,可以通过使用分隔符来标记它。但两者的出现频率是一样的。因此,从算法的角度来看,这两个结果都是准确的:|,|

正确结果

test1,2
test3,4
test5

错误的结果

test1
2|test3
4|test5

如果您提出一组准则,或者可以以某种方式控制CSV文件的生成,那么您可以尝试使用上述字符列表来查找与方法一起使用的分隔符。例如:String.contains()

public class MyClass {

    private List<String> delimiterList = new ArrayList<>(){{
        add(",");
        add(";");
        add("\t");
        // etc...
    }};

    private static String determineDelimiter(String text) {
        for (String delimiter : delimiterList) {
            if(text.contains(delimiter)) {
                return delimiter;
            }
        }
        return "";
    }

    public static void main(String[] args) {
        String csvFile = "/Users/csv/country.csv";
        String line = "";
        String cvsSplitBy = ",";
        String delimiter = "";
        boolean firstLine = true;
        try (BufferedReader br = new BufferedReader(new FileReader(csvFile)))  {
            while ((line = br.readLine()) != null) {
                if(firstLine) {
                    delimiter = determineDelimiter(line);
                    if(delimiter.equalsIgnoreCase("")) {
                        System.out.println("Unsupported delimiter found: " + delimiter);
                        return;
                    }
                    firstLine = false;
                }
                // use comma as separator
                String[] country = line.split(delimiter);
                System.out.println("Country [code= " + country[4] + " , name=" + country[5] + "]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

更新

为了更优化,可以在方法而不是循环中使用正则表达式。determineDelimiter()for-each