Java 如何确定CSV文件中的分隔符
我有一个场景,我必须解析来自不同来源的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
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…)因此,有时您的文件应该按,
,有时按(
)分割,并且每个文件都应该允许出现非分隔符字符?我不知道这样的代码是否可以在没有链接的情况下进行编码