如何在忽略转义逗号的同时拆分逗号分隔的String?

我需要编写一个StringUtils.commaDelimitedListToStringArray函数的扩展版本,它获取一个额外的参数:escape char。

所以打电话给我:

commaDelimitedListToStringArray("test,test\\,test\\,test,test", "\\") 

应该返回:

 ["test", "test,test,test", "test"] 

我目前的尝试是使用String.split()使用正则表达式拆分String:

 String[] array = str.split("[^\\\\],"); 

但返回的数组是:

 ["tes", "test\,test\,tes", "test"] 

有任何想法吗?

正则表达式

 [^\\], 

表示“匹配一个不是反斜杠后跟逗号的字符” – 这就是为什么t,模式匹配,因为t是一个不是反斜杠的字符。

我认为你需要使用某种负面的lookbehind ,来捕获一个没有捕获前面的字符的\前面的字符,类似于

 (? 

(顺便说一句,请注意我有意没有双重逃脱反斜杠以使其更具可读性)

尝试:

 String array[] = str.split("(? 

基本上这是用逗号分隔,除了逗号前面有两个反斜杠。 这称为负后观零宽度断言 。

不要重新发明轮子。

为了将来参考,这是我最终得到的完整方法:

 public static String[] commaDelimitedListToStringArray(String str, String escapeChar) { // these characters need to be escaped in a regular expression String regularExpressionSpecialChars = "/.*+?|()[]{}\\"; String escapedEscapeChar = escapeChar; // if the escape char for our comma separated list needs to be escaped // for the regular expression, escape it using the \ char if(regularExpressionSpecialChars.indexOf(escapeChar) != -1) escapedEscapeChar = "\\" + escapeChar; // see http://stackoverflow.com/questions/820172/how-to-split-a-comma-separated-string-while-ignoring-escaped-commas String[] temp = str.split("(? 

正如matt b所说, [^\\],会将逗号前面的字符解释为分隔符的一部分。

 "test\\\\\\,test\\\\,test\\,test,test" -(split)-> ["test\\\\\\,test\\\\,test\\,tes" , "test"] 

正如drvdijk所说, (?会误解逃脱的反斜杠。

 "test\\\\\\,test\\\\,test\\,test,test" -(split)-> ["test\\\\\\,test\\\\,test\\,test" , "test"] -(unescape commas)-> ["test\\\\,test\\,test,test" , "test"] 

我希望能够逃脱反斜杠......

 "test\\\\\\,test\\\\,test\\,test,test" -(split)-> ["test\\\\\\,test\\\\" , "test\\,test" , "test"] -(unescape commas and backslashes)-> ["test\\,test\\" , "test,test" , "test"] 

drvdijk建议(?<=(?适用于包含最多100个反斜杠的元素的列表。 这远远不够......但为什么要限制? 有没有更有效的方式(不贪婪)? 无效字符串呢?

我搜索了一段通用解决方案,然后我自己编写了这个东西......想法是按照匹配列表元素的模式进行拆分(而不是匹配分隔符)。

我的回答并没有将转义字符作为参数。

 public static List commaDelimitedListStringToStringList(String list) { // Check the validity of the list // ex: "te\\st" is not valid, backslash should be escaped if (!list.matches("^(([^\\\\,]|\\\\,|\\\\\\\\)*(,|$))+")) { // Could also raise an exception return null; } // Matcher for the list elements Matcher matcher = Pattern .compile("(?<=(^|,))([^\\\\,]|\\\\,|\\\\\\\\)*(?=(,|$))") .matcher(list); ArrayList result = new ArrayList(); while (matcher.find()) { // Unescape the list element result.add(matcher.group().replaceAll("\\\\([\\\\,])", "$1")); } return result; } 

模式描述(未转义):

(?<=(^|,)) forward是字符串或a的开头,

([^\\,]|\\,|\\\\)*\, ,, \\或字符组成的元素既不是\也不,

(?=(,|$))后面是字符串结尾或a ,

该模式可以简化。

即使使用3个解析( matches + find + replaceAll ),此方法似乎比drvdijk建议的更快。 它仍然可以通过编写特定的解析器进行优化。

另外,如果只有一个字符是特殊的,那么有一个转义字符的需要是什么,它可以简单地加倍...

 public static List commaDelimitedListStringToStringList2(String list) { if (!list.matches("^(([^,]|,,)*(,|$))+")) { return null; } Matcher matcher = Pattern.compile("(?<=(^|,))([^,]|,,)*(?=(,|$))") .matcher(list); ArrayList result = new ArrayList(); while (matcher.find()) { result.add(matcher.group().replaceAll(",,", ",")); } return result; }