我的程序从文件中读取一行。这一行包含逗号分隔的文本,如:
123,test,444,"don't split, this",more test,1
我希望分裂的结果是:
123
test
444
"don't split, this"
more test
1
如果我使用String.split(",")
,我会得到这个:
123
test
444
"don't split
this"
more test
1
换句话说:子字符串"don't split, this"
中的逗号不是分隔符。怎么处理这个?
提前致谢.. 雅各布
答案 0 :(得分:91)
你可以试试这个正则表达式:
str.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
这会将,
上的字符串拆分,后跟偶数个双引号。换句话说,它在双引号之外的逗号上拆分。如果你的字符串中有平衡的引号,这将有效。
说明:
, // Split on comma
(?= // Followed by
(?: // Start a non-capture group
[^"]* // 0 or more non-quote characters
" // 1 quote
[^"]* // 0 or more non-quote characters
" // 1 quote
)* // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
[^"]* // Finally 0 or more non-quotes
$ // Till the end (This is necessary, else every comma will satisfy the condition)
)
您甚至可以在代码中使用(?x)
修饰符和正则表达式进行类似的操作。修饰符忽略了正则表达式中的任何空格,因此更容易读取分为多行的正则表达式,如下所示:
String[] arr = str.split("(?x) " +
", " + // Split on comma
"(?= " + // Followed by
" (?: " + // Start a non-capture group
" [^\"]* " + // 0 or more non-quote characters
" \" " + // 1 quote
" [^\"]* " + // 0 or more non-quote characters
" \" " + // 1 quote
" )* " + // 0 or more repetition of non-capture group (multiple of 2 quotes will be even)
" [^\"]* " + // Finally 0 or more non-quotes
" $ " + // Till the end (This is necessary, else every comma will satisfy the condition)
") " // End look-ahead
);
答案 1 :(得分:11)
为什么在可以匹配时拆分?
恢复这个问题是因为出于某种原因,没有提到简单的解决方案。这是我们精美紧凑的正则表达式:
"[^"]*"|[^,]+
这将匹配所有所需的片段(see demo)。
<强>解释强>
"[^"]*"
,我们匹配完整的"double-quoted strings"
|
[^,]+
任何不是逗号的字符。一种可能的改进是改进交替的字符串方面,以允许引用的字符串包含转义引号。
答案 2 :(得分:1)
如果没有复杂的正则表达式,您可以轻松完成此任务:
"
。你得到一个字符串列表如果你想处理'''的引用,你必须稍微调整算法(加入一些部分,你错误地拆分或改变拆分为简单的正则表达式),但基本结构仍然存在。
所以基本上是这样的:
public class SplitTest {
public static void main(String[] args) {
final String splitMe="123,test,444,\"don't split, this\",more test,1";
final String[] splitByQuote=splitMe.split("\"");
final String[][] splitByComma=new String[splitByQuote.length][];
for(int i=0;i<splitByQuote.length;i++) {
String part=splitByQuote[i];
if (i % 2 == 0){
splitByComma[i]=part.split(",");
}else{
splitByComma[i]=new String[1];
splitByComma[i][0]=part;
}
}
for (String parts[] : splitByComma) {
for (String part : parts) {
System.out.println(part);
}
}
}
}
承诺给lambda这个会更干净!
答案 3 :(得分:0)
请参阅以下代码段。此代码仅考虑快乐流程。根据您的要求更改
public static String[] splitWithEscape(final String str, char split,
char escapeCharacter) {
final List<String> list = new LinkedList<String>();
char[] cArr = str.toCharArray();
boolean isEscape = false;
StringBuilder sb = new StringBuilder();
for (char c : cArr) {
if (isEscape && c != escapeCharacter) {
sb.append(c);
} else if (c != split && c != escapeCharacter) {
sb.append(c);
} else if (c == escapeCharacter) {
if (!isEscape) {
isEscape = true;
if (sb.length() > 0) {
list.add(sb.toString());
sb = new StringBuilder();
}
} else {
isEscape = false;
}
} else if (c == split) {
list.add(sb.toString());
sb = new StringBuilder();
}
}
if (sb.length() > 0) {
list.add(sb.toString());
}
String[] strArr = new String[list.size()];
return list.toArray(strArr);
}
答案 4 :(得分:0)
基于 @ zx81&#39; s 答案,因为匹配的想法非常好,我已经添加了Java 9 results
来电,返回Stream
。由于OP希望使用split
,我已收集到String[]
,split
。
请注意,如果逗号分隔符后面有空格(a, b, "c,d"
)。然后你需要改变模式。
$ jshell
-> String so = "123,test,444,\"don't split, this\",more test,1";
| Added variable so of type String with initial value "123,test,444,"don't split, this",more test,1"
-> Pattern.compile("\"[^\"]*\"|[^,]+").matcher(so).results();
| Expression value is: java.util.stream.ReferencePipeline$Head@2038ae61
| assigned to temporary variable $68 of type java.util.stream.Stream<MatchResult>
-> $68.map(MatchResult::group).toArray(String[]::new);
| Expression value is: [Ljava.lang.String;@6b09bb57
| assigned to temporary variable $69 of type String[]
-> Arrays.stream($69).forEach(System.out::println);
123
test
444
"don't split, this"
more test
1
String so = "123,test,444,\"don't split, this\",more test,1";
Pattern.compile("\"[^\"]*\"|[^,]+")
.matcher(so)
.results()
.map(MatchResult::group)
.toArray(String[]::new);
[^"]
匹配:引用,除引号外的任何内容,引用。[^"]*
匹配:引用,除引号0(或更多)以外的任何内容,引用。[^,]+
- 将&#34 ;赢&#34; results()
需要Java 9或更高版本。Stream<MatchResult>
,我使用group()
调用映射并收集到字符串数组。无参数toArray()
调用将返回Object[]
。