如何利用正反向后断言匹配及解决带引号字符串按逗号分割问题
问题1:用否定断言实现「前后无特定模式时匹配目标」
要搞定这个需求,核心就是组合使用反向否定后断言((?<!...))和正向否定预断言((?!...)):
(?<!X):保证当前位置左边绝对没有匹配X的内容(?!X):保证当前位置右边绝对没有匹配X的内容
举个直观的例子:假设你要匹配单词apple,但不想匹配那些前后跟着数字的(比如123apple或apple456),那正则就可以这么写:
(?<!\d)apple(?!\d)
这样只有当apple前后都不是数字时,才会被匹配到。如果你的特定模式是更复杂的短语,直接把X换成对应的模式就行。
问题2:分割字符串时跳过引号包裹的逗号
你的思路方向是对的,但原正则有两个坑导致失效:
- 错误的字符范围:
[0-z]看起来是想匹配字母数字,但ASCII码里0到z包含了一堆非字母数字的符号(比如:、@、[),你实际需要的是「引号内的非引号字符」,应该用[^"]*(表示除引号之外的任意字符)。 - 逻辑不严谨:原断言只能检查逗号左边是「引号开头的一串字符」,碰到多组引号的情况就会翻车,比如
"a,b",c,"d,e"这种字符串,原正则会错误分割中间的逗号。
靠谱的解决方案
我们换个思路:只分割那些不在引号内部的逗号。怎么判断逗号不在引号里?看逗号后面的引号总数是不是偶数——如果是,说明这个逗号在引号外面。对应的正则是:
,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)
拆解一下这个正则的逻辑:
,:就是我们要找的分割用逗号(?=...):正向预断言,检查逗号后面的内容:(?:[^"]*"[^"]*")*:匹配0或多组「非引号字符+引号+非引号字符+引号」,也就是成对出现的引号[^"]*$:最后剩下的内容里没有引号,确保整个字符串从逗号往后的引号总数是偶数
修正后的代码
String s = "today,\"is, clear\",and sunny"; String[] split = s.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); // 输出结果正好是你要的:["today", "\"is, clear\"", "and sunny"]
测试一下就知道,这个代码完美符合你的预期。另外提一句,如果你的字符串里有转义引号(比如"he said \"hello\""),这个正则会失效,不过如果只是普通的未转义引号,这个方案完全够用。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

