如何在忽略转义逗号的同时拆分逗号分隔的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; }