分隔字符串,但忽略引号中的逗号
我有一个像这样的字符串:
foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"
我想用逗号分割 - 但我需要忽略引号中的逗号。 我怎样才能做到这一点? 似乎正则表达式的方法失败; 我想我可以手动扫描并在看到报价时进入不同的模式,但使用预先存在的库会很好。 (编辑:我想我是指已经是JDK一部分的库,或者已经是Apache Commons等常用库的一部分)。
上面的字符串应该分成:
foo
bar
c;qual="baz,blurb"
d;junk="quux,syzygy"
注意:这不是一个CSV文件,它是包含在具有较大整体结构的文件中的单个字符串
尝试:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"";
String[] tokens = line.split(",(?=(?:[^"]*"[^"]*")*[^"]*$)", -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
输出:
> foo
> bar
> c;qual="baz,blurb"
> d;junk="quux,syzygy"
换句话说:只有当逗号为零,或者在它之前有偶数的引号时,才会在逗号分割。
或者,对眼睛有点友善:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"";
String otherThanQuote = " [^"] ";
String quotedString = String.format(" " %s* " ", otherThanQuote);
String regex = String.format("(?x) "+ // enable comments, ignore white spaces
", "+ // match a comma
"(?= "+ // start positive look ahead
" (?: "+ // start non-capturing group 1
" %s* "+ // match 'otherThanQuote' zero or more times
" %s "+ // match 'quotedString'
" )* "+ // end group 1 and repeat it zero or more times
" %s* "+ // match 'otherThanQuote'
" $ "+ // match the end of the string
") ", // stop positive look ahead
otherThanQuote, quotedString, otherThanQuote);
String[] tokens = line.split(regex, -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
这与第一个例子相同。
编辑
正如@MikeFHay在评论中提到的那样:
我更喜欢使用Guava的Splitter,因为它具有更为理想的默认值(参见上面关于由String#split()
修剪的空匹配的讨论,所以我这样做了:
Splitter.on(Pattern.compile(",(?=(?:[^"]*"[^"]*")*[^"]*$)"))
尽管我喜欢正则表达式,但对于这种依赖于状态的标记化,我相信一个简单的解析器(在这种情况下,比这个单词更简单,可能会使它听起来更简单)可能是一个更干净的解决方案,特别是关于可维护性,例如:
String input = "foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"";
List<String> result = new ArrayList<String>();
int start = 0;
boolean inQuotes = false;
for (int current = 0; current < input.length(); current++) {
if (input.charAt(current) == '"') inQuotes = !inQuotes; // toggle state
boolean atLastChar = (current == input.length() - 1);
if(atLastChar) result.add(input.substring(start));
else if (input.charAt(current) == ',' && !inQuotes) {
result.add(input.substring(start, current));
start = current + 1;
}
}
如果你不关心在引号内保留逗号,你可以简化这种方法(不处理开始索引,没有最后一个字符的特殊情况),用逗号替换你的逗号,然后用逗号分隔:
String input = "foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"";
StringBuilder builder = new StringBuilder(input);
boolean inQuotes = false;
for (int currentIndex = 0; currentIndex < builder.length(); currentIndex++) {
char currentChar = builder.charAt(currentIndex);
if (currentChar == '"') inQuotes = !inQuotes; // toggle state
if (currentChar == ',' && inQuotes) {
builder.setCharAt(currentIndex, ';'); // or '♡', and replace later
}
}
List<String> result = Arrays.asList(builder.toString().split(","));
http://sourceforge.net/projects/javacsv/
https://github.com/pupi1985/JavaCSV-Reloaded(前一个库的分支将允许生成的输出具有Windows行终止符rn
而不运行Windows时)
http://opencsv.sourceforge.net/
适用于Java的CSV API
你能推荐一个Java库来读取(也可能写入)CSV文件吗?
Java库或应用程序将CSV转换为XML文件?
链接地址: http://www.djcxy.com/p/36967.html上一篇: separated string but ignoring commas in quotes
下一篇: How to convert timestamp with milliseconds to date in Oracle