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

Java 如何确定CSV文件中的分隔符,java,csv,Java,Csv,我有一个场景,我必须解析来自不同来源的CSV文件,解析代码非常简单明了 String csvFile = "/Users/csv/country.csv"; String line = ""; String cvsSplitBy = ","; try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) { while ((line

我有一个场景,我必须解析来自不同来源的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分隔符,我有许多不同的格式,有时是
有时是

是否有任何方法在解析文件之前确定分隔符字符取决于

如果您的数据集总是相同的长度和/或分隔符从未出现在数据列中,您可以只读取文件的第一行,查看其中的longed for separator,设置它,然后使用该分隔符读取文件的其余部分

差不多

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
        if (line.contains(",")) {
            cvsSplitBy = ",";
        } else if (line.contains(";")) {
           cvsSplitBy = ";";
        } else {
            System.out.println("Wrong separator!");
        }
        String[] country = line.split(cvsSplitBy);
        System.out.println("Country [code= " + country[4] + " , name=" + country[5] + "]");
    }
} catch (IOException e) {
    e.printStackTrace();
}

Greetz Kai

添加这样一个条件

String [] country;
if(line.contains(",")
    country = line.split(",");
else if(line.contains(";"))
    country=line.split(";");
是,但仅当分隔符字符不允许作为常规文本存在时 最简单的答案是列出所有可用的分隔符字符,并尝试识别正在使用的字符。即使如此,您也必须对文件或创建文件的人员设置一些限制。请看以下两种情况:

案例1-文件.csv的内容

test,test2,test3
test1|test2,3|test4
案例2-文件.csv的内容

test,test2,test3
test1|test2,3|test4
如果您事先知道分隔符字符,则可以使用
拆分第一个字符串,使用
|
拆分第二个字符串,得到相同的结果。但是,如果您试图通过解析文件来识别分隔符,两个字符串可以使用
字符进行拆分,您将得到以下结果:

案例1-使用

test1
test2
test3
test1|test2
3|test4
案例2-使用

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

最坏情况

test1,2|test3,4|test5
通过查看文本,可以使用
|
作为分隔符来标记它。但是
的出现频率是相同的。因此,从算法的角度来看,两个结果都是准确的:

正确结果

test1,2
test3,4
test5
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();
        }
    }
}
公共类MyClass{
private List delimiterList=new ArrayList(){{
加上(“,”);
加上(“;”);
加上(“\t”);
//等等。。。
}};
专用静态字符串限定符(字符串文本){
for(字符串分隔符:delimiterList){
if(text.contains(分隔符)){
返回分隔符;
}
}
返回“”;
}
公共静态void main(字符串[]args){
字符串csvFile=“/Users/csv/country.csv”;
字符串行=”;
字符串cvsSplitBy=“,”;
字符串分隔符=”;
布尔第一行=真;
try(BufferedReader br=new BufferedReader(new FileReader(csvFile))){
而((line=br.readLine())!=null){
如果(第一线){
分隔符=限定符(行);
if(分隔符.equalsIgnoreCase(“”){
System.out.println(“找到不支持的分隔符:“+分隔符”);
返回;
}
firstLine=false;
}
//使用逗号作为分隔符
String[]country=line.split(分隔符);
System.out.println(“国家[code=“+Country[4]+”,name=“+Country[5]+”]”);
}
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
更新

test1,2|test3,4|test5

对于更优化的方法,在
determineDelimiter()
方法中,而不是在每个
循环中使用
,您可以使用正则表达式。

如果分隔符可以出现在数据列中,那么您是在要求不可能的结果。例如,考虑CSV文件的第一行:

one,two:three
这可以是逗号分隔的文件,也可以是冒号分隔的文件。你不知道它是哪种类型的

如果您可以保证第一行的所有列都用引号括起来,例如,如果它总是这种格式:

"one","two","three"
然后,您可以使用此逻辑(尽管它不是100%防弹的):

如果不能保证这样的受限格式,那么最好将分隔符字符作为参数传递

然后,您可以使用广为人知的开源CSV解析器读取文件,例如。

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

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();
CsvParserSettings设置=新的CsvParserSettings();
settings.detectFormatAutomatically();
CsvParser parser=新的CsvParser(设置);
List rows=parser.parseAll(新文件(“/path/to/your.csv”);
//如果你想看看它检测到了什么
CsvFormat format=parser.getDetectedFormat();
免责声明:我是这个图书馆的作者,我确保涵盖了各种各样的角落案例。它是开源和免费的(Apache 2.0许可证)


希望这有帮助。

我有很多不同的格式。允许设置什么分隔符?逗号,冒号,分号…?@zlakad,是的,逗号,冒号,分号你需要用逗号来处理十进制分隔符的数字吗?(通常他们使用逗号以外的其他字符作为字段sep…)因此,有时您的文件应该按
,有时按
)分割,并且每个文件都应该允许出现非分隔符字符?我不知道这样的代码是否可以在没有链接的情况下进行编码