我正在尝试使用标准Java库解析用引号括起来的逗号分隔值(我知道这一定是可能的)
作为示例,file.txt包含每行
的新行"Foo","Bar","04042013","04102013","Stuff"
"Foo2","Bar2","04042013","04102013","Stuff2"
但是,当我使用目前编写的代码解析文件时:
import java.io.*;
import java.util.Arrays;
public class ReadCSV{
public static void main(String[] arg) throws Exception {
BufferedReader myFile = new BufferedReader(new FileReader("file.txt"));
String myRow = myFile.readLine();
while (myRow != null){
//split by comma separated quote enclosed values
//BUG - first and last values get an extra quote
String[] myArray = myRow.split("\",\""); //the problem
for (String item:myArray) { System.out.print(item + "\t"); }
System.out.println();
myRow = myFile.readLine();
}
myFile.close();
}
}
然而输出是
"Foo Bar 04042013 04102013 Stuff"
"Foo2 Bar2 04042013 04102013 Stuff2"
而不是
Foo Bar 04042013 04102013 Stuff
Foo2 Bar2 04042013 04102013 Stuff2
我知道我在Split上出错了,但我不确定如何解决它。
答案 0 :(得分:4)
在进行拆分之前,只需使用下面的行删除myRow变量中的第一个双引号和最后一个双引号。
myRow = myRow.substring(1, myRow.length() - 1);
(更新)同时检查myRow是否为空。否则上面的代码将导致异常。例如,下面的代码检查myRow是否为空,然后只删除字符串中的双引号。
if (!myRow.isEmpty()) {
myRow = myRow.substring(1, myRow.length() - 1);
}
答案 1 :(得分:4)
我认为你可能不得不采用有状态的方法,基本上就像下面的代码一样(如果你想允许在值中转义引号,则需要另一个状态):
import java.util.ArrayList;
import java.util.List;
public class CSV {
public static void main(String[] args) {
String s = "\"hello, i am\",\"a string\"";
String x = s;
List<String> l = new ArrayList<String>();
int state = 0;
while(x.length()>0) {
if(state == 0) {
if(x.indexOf("\"")>-1) {
x = x.substring(x.indexOf("\"")+1).trim();
state = 1;
} else {
break;
}
} else if(state == 1) {
if(x.indexOf("\"")>-1) {
String found = x.substring(0,x.indexOf("\""));
System.err.println("found: "+found);
l.add(found);
x = x.substring(x.indexOf("\"")+1).trim();
state = 0;
} else {
throw new RuntimeException("bad format");
}
} else if(state == 2) {
if(x.indexOf(",")>-1) {
x = x.substring(x.indexOf(",")+1).trim();
state = 0;
} else {
break;
}
}
}
for(String f : l) {
System.err.println(f);
}
}
}
答案 2 :(得分:2)
相反,您可以使用replaceAll,对我来说,这看起来更适合此任务:
myRow = myRow.replaceAll("\"", "").replaceAll(","," ");
这将替换所有"
没有任何内容(将删除它们),然后它将用空格替换所有,
(当然,您可以增加空格数)。
答案 3 :(得分:1)
上面代码段中的问题是您要根据","
拆分字符串。
在您的热线上"foo","
开始{结尾","stuff"
,起始和结束引号与","
不匹配,因此没有分割。
所以这绝对不是java中的错误。在您的情况下,您需要自己处理该部分。
您有多种选择。其中一些可能如下。
1.如果您确定始终有一个起始"
和结束"
,您可以在分割之前将其从字符串中删除。
2.如果起始"
和"
是可选的,您可以先使用startsWith
endsWith
进行检查,然后在拆分前删除。
答案 4 :(得分:0)
你可以简单地用逗号分隔字符串,然后删除第一个和最后一个'“'。=) 希望这很有帮助 没有太多时间:D
String s = "\"Foo\",\"Bar\",\"04042013\",\"04102013\",\"Stuff\"";
String[] bufferArray = new String[10];
String bufferString;
int i = 0;
System.out.println(s);
Scanner scanner = new Scanner(s);
scanner.useDelimiter(",");
while(scanner.hasNext()) {
bufferString = scanner.next();
bufferArray[i] = bufferString.subSequence(1, bufferString.length() - 1).toString();
i++;
}
System.out.println(bufferArray[0]);
System.out.println(bufferArray[1]);
System.out.println(bufferArray[2]);
答案 5 :(得分:0)
此解决方案不如String.split()
oneliner优雅。优点是我们避免了脆弱的字符串操作,即。使用String.substring()
。但字符串必须以,"
结尾。
此版本处理分隔符之间的空格。引号中的分隔符字符将按预期被忽略,与转义引号一样(例如\"
)。
String s = "\"F\\\",\\\"oo\" , \"B,ar\",\"04042013\",\"04102013\",\"St,u\\\"ff\"";
Pattern p = Pattern.compile("(.*?)\"\\s*,\\s*\"");
Matcher m = p.matcher(s + ",\""); // String must end with ,"
while (m.find()) {
String result = m.group(1);
System.out.println(result);
}