Java 逗号外引号上的拆分
我的程序从文件中读取一行。此行包含逗号分隔的文本,如:Java 逗号外引号上的拆分,java,regex,string,split,Java,Regex,String,Split,我的程序从文件中读取一行。此行包含逗号分隔的文本,如: 123,test,444,"don't split, this",more test,1 我希望拆分的结果如下: 123 test 444 "don't split, this" more test 1 如果我使用字符串.split(“,”,我将得到以下结果: 123 test 444 "don't split this" more test 1 换句话说:子字符串中的逗号“不拆分,此”不是分隔符。如何处理此问题?您可以试用此正则表
123,test,444,"don't split, this",more test,1
我希望拆分的结果如下:
123
test
444
"don't split, this"
more test
1
如果我使用字符串.split(“,”
,我将得到以下结果:
123
test
444
"don't split
this"
more test
1
换句话说:子字符串
中的逗号“不拆分,此”
不是分隔符。如何处理此问题?您可以试用此正则表达式:
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
);
无需复杂的正则表达式,即可轻松完成此操作:
“
上拆分。您将得到一个字符串列表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);
}
}
}
}
公共类拆分测试{
公共静态void main(字符串[]args){
最后一个字符串splitMe=“123,test,444,\“不要拆分,这个\”,更多测试,1”;
最后一个字符串[]splitByQuote=splitMe.split(“\”);
最终字符串[][]splitByComma=新字符串[splitByQuote.length]];
对于(int i=0;i请参见下面的代码段。此代码仅考虑快乐流。根据您的要求更改
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);
}
publicstaticstring[]splitWithEscape(最终字符串str,charsplit,
字符(字符){
最终列表=新的LinkedList();
char[]cArr=str.toCharArray();
布尔isEscape=false;
StringBuilder sb=新的StringBuilder();
用于(字符c:cArr){
if(isEscape&&c!=转义字符){
sb.附加(c);
}else if(c!=split&&c!=escapeCharacter){
sb.附加(c);
}else if(c==转义字符){
如果(!isEscape){
isEscape=真;
如果(sb.length()>0){
添加(sb.toString());
sb=新的StringBuilder();
}
}否则{
isEscape=假;
}
}如果(c==split),则为else{
添加(sb.toString());
sb=新的StringBuilder();
}
}
如果(sb.length()>0){
添加(sb.toString());
}
String[]strArr=新字符串[list.size()];
返回列表。toArray(strArr);
}
如果可以匹配,为什么要拆分?
由于某种原因,没有提到简单的解决方案,因此重新提出了这个问题。这是我们的漂亮紧凑的正则表达式:
"[^"]*"|[^,]+
这将匹配所有需要的片段()
解释
- 使用
“[^”]*”
,我们匹配完整的“双引号字符串”
- 或
|
- 我们匹配任何非逗号的字符
一种可能的改进是改进替换的字符串端,以允许引用的字符串包含转义引号。基于@zx81的答案,因为匹配的想法非常好,我添加了Java 9
调用,它返回一个流
。因为OP想要使用spl它
,我已经收集到String[]
,就像split
一样
注意:如果逗号分隔符(a,b,“c,d”)后面有空格,则需要更改模式。
Jshell演示
解释
Regex[^”]
匹配:一个引号,除引号外的任何内容,一个引号
Regex[^”]*
匹配:一个引号,除引号0(或更多)次外的任何内容,一个引号
该正则表达式需要首先进入“win”,否则匹配除逗号以外的任何内容1次或多次,即:[^,]+
-将“win”
results()
需要Java 9或更高版本
它返回Stream
,我使用group()
调用和collect将其映射到字符串数组。无参数toArray()
调用将返回Object[]
为什么这是一个要求?你能提供更多关于你试图解决的问题的信息吗?这些年来,这个答案仍然很有价值!让我的程序与你的解释一起工作。谢谢!现在,有什么方法可以添加换行符吗?\n和\r?嗨,我的字符串是这样的:\“不要拆分,这个\”(它前面有那些反斜杠。)如何修改正则表达式呢?嗨,Rohit,我遵循了你的解决方案,我有两个分隔符,和/或。并在正则表达式后面使用:(\s+和\s+)\s+或\s+(=(?:[^\“]*”[^\“]*”[^\“]*”[^\“]*$)。它对大多数用例都很有效,但输入失败:'brand=='Kellogg\'s'或country='UnitedStates和“India\”。你能帮帮我吗?我对regex很陌生。这不适用于非普通情况,例如,如果文本本身包含引号,则需要转义,如\“
因为我更喜欢这个,而不是拆分,所以我将它与Matcher中的Java 9改进结合起来,允许流式处理。我的答案包含jshell会话演示它。如果您还需要获取空字符串,这个解决方案将不起作用,但我喜欢它。@zx81您知道如何使用转义引号\”使它起作用吗?”?
$ 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);