用于匹配字符的正则表达式,但不是在用引号括起来时

时间:2009-09-18 09:05:01

标签: regex

我需要在字符串中匹配冒号(':'),但不能用引号括起来 - 不是“或”字符。

所以以下应该有2场比赛

something:'firstValue':'secondValue'    
something:"firstValue":'secondValue'

但这应该只有1个匹配

something:'no:match'

5 个答案:

答案 0 :(得分:4)

如果正则表达式实现支持环视声明,请尝试:

:(?:(?<=["']:)|(?=["']))

这将匹配任何前面或后面跟着双引号或单引号的冒号。所以这只考虑你提到的构造。 <{1}}不匹配。

如果你构建一个逐字节读取输入的小解析器并记住引用打开时会更好。

答案 1 :(得分:3)

正则表达式是无状态的。跟踪您是否在引号内是状态信息。因此,仅使用单个正则表达式无法正确处理此问题。 (请注意,一些“正则表达式”实现添加了可能使这成为可能的扩展;我在这里只谈论“真正的”正则表达式。)

使用两个正则表达式可以这样做,但前提是您愿意修改原始字符串或使用它的副本。在Perl:

$string =~ s/['"][^'"]*['"]//g;
my $match_count = $string =~ /:/g;

第一个将找到由引号组成的每个序列,后跟任意数量的非引号字符,并以第二个引号终止,并从字符串中删除所有此类序列。这将消除引号内的任何冒号。 (something:"firstValue":'secondValue'变为something::something:'no:match'变为something:

第二个是对剩余冒号的简单计数,这些冒号将不在引号内。

在大多数情况下,仅计算未引用的冒号似乎并不是一件特别有用的事情,所以我怀疑你的真正目标是将字符串拆分为以冒号作为字段分隔符的字段,在这种情况下,这种基于正则表达式的解决方案是不合适的,因为它会破坏引用字段中的任何数据。在这种情况下,您需要使用一个真正的解析器(大多数CSV解析器允许您指定分隔符并且对于此是理想的),或者在最坏的情况下,逐个字符地遍历字符串并手动拆分。 / p>

如果您告诉我们您正在使用的语言,我相信有人可以为该语言推荐一个好的解析器库。

答案 2 :(得分:1)

Uppps ...错过了重点。忘了剩下的。这很难做到,因为正则表达式并不擅长计算平衡字符(例如.NET实现有一个扩展可以做到,但它有点复杂)。

您可以使用否定的字符组来执行此操作。

[^'"]:[^'"]

您可以在非捕获组中进一步包装引号。

(?:[^'"]):(?:[^'"])

或者你可以使用断言。

(?<!['"]):(?!['"])

答案 3 :(得分:0)

我想出了以下稍微令人担忧的结构:

(?<=^('[^']*')*("[^"]*")*[^'"]*):

它使用lookbehind断言来确保匹配从行开头到当前冒号的偶数引号。它允许在双引号内嵌入单引号,反之亦然。如:

'a":b':c::"':"(在第6,8和9位匹配)

修改

Gumbo是对的,不允许在断言后面使用*

答案 4 :(得分:0)

您可以尝试使用引号将字符串捕获

/(?<q>'|")([\w ]+)(\k<q>)/m

第一个模式定义了允许的报价类型,第二个模式使用所有单词数字和空格。 此解决方案的一个很好的优点是,它仅需使用引号引起来的字符串。

Try it at regex101.com