Regex 使用正则表达式,如何有效地在双引号和嵌入双引号之间匹配字符串?
让我们有一个文本,其中我们希望匹配双引号之间的所有字符串;但在这些双引号中,可以引用双引号。例如:Regex 使用正则表达式,如何有效地在双引号和嵌入双引号之间匹配字符串?,regex,Regex,让我们有一个文本,其中我们希望匹配双引号之间的所有字符串;但在这些双引号中,可以引用双引号。例如: "He said \"Hello\" to me for the first time" 使用正则表达式,如何有效地匹配这些输入?匹配这些输入的一个非常有效的解决方案是使用normal*(special normal*)*模式;这个名字引自杰弗里·弗里德尔的优秀著作 通常,这是一种有用的模式,用于将由常规条目(正常部分)组成的输入与中间的分隔符(特殊部分)进行匹配 注意,就像所有的东西regex
"He said \"Hello\" to me for the first time"
使用正则表达式,如何有效地匹配这些输入?匹配这些输入的一个非常有效的解决方案是使用
normal*(special normal*)*
模式;这个名字引自杰弗里·弗里德尔的优秀著作
通常,这是一种有用的模式,用于将由常规条目(正常部分)组成的输入与中间的分隔符(特殊部分)进行匹配
注意,就像所有的东西regex一样,它应该在没有更好的选择时使用;例如,虽然可以使用此模式解析CSV数据,但如果使用Java,则最好使用OpenCSV
还请注意,虽然模式名称中的量词是星(即零或更多),但您可以根据需要更改它们
嵌入双引号的字符串
让我们再举一次上面的例子;请考虑此文本示例可能在您输入的任何地方:
"He said \"Hello\" to me for the first time"
不管你怎么努力,再多的“点加贪婪/懒惰量词”魔法也帮不了你解决这个问题。相反,将引号之间的输入分类为普通和特殊:
- 正常情况下不是反斜杠或双引号:
[^\\\”]
- 特殊是反斜杠后跟双引号的顺序:
\\“
normal*(special normal*)*
模式,将得到以下正则表达式:
[^\\"]*(\\"[^\\"]*)*
在前后添加双引号以匹配全文将生成最终正则表达式:
"[^\\"]*(\\"[^\\"]*)*"
您将注意到,这也将匹配带引号的空字符串
带破折号分隔符的单词
在这里,我们必须对量词使用变体,因为:
- 我们不想要空话
- 我们不想要以破折号开头的词
- 当破折号出现时,它必须在另一个破折号之前至少有一个字母(如果有的话)
the-word-to-match
让我们再次分解为正常和特殊:
- 普通:小写ASCII字母:
李>[a-z]
- 特殊:破折号:
-
[a-z]*(-[a-z]*)*
但正如我们所说:
- 我们不希望单词以破折号开头:第一个
应该变成*
李>+
- 当发现破折号时,破折号后面至少应该有一个字母:第二个
应该变成*
+
[a-z]+(-[a-z]+)*
在其周围添加单词锚以获得最终结果:
\b[a-z]+(-[a-z]+)*\b
其他操作员变体
上面的示例仅限于将*
替换为+
,但当然,您可以根据自己的需要进行多种变体。一个非常经典的例子是IP地址:
- 正常值最多为三位数(
)\d{1,3}
- 特殊的是点:(
)\.
- 第一个
只出现一次,因此没有量词normal
中的(特殊正常*)
也只出现一次,因此没有量词normal
- 最后,
部分正好出现三次,因此(特殊正常*)
{3}
- 很可能您不需要(或不想)捕获重复部分(特殊正常*)部分);因此,建议您使用非捕获组。例如,对带引号的字符串使用
。事实上,如果您需要,在这种情况下,捕获几乎永远不会得到所需的结果,因为重复一个捕获组只会给您最后一次捕获(所有以前的重复都将被覆盖),除非您在.NET中使用此模式。(谢谢@ohaal)“[^\\”]*(?:\\“[^\\”]*)*”
“[^\\”]*(\\“[^\\”]*)*”
)@ohaal,这是正确的(应该在提示部分或其他地方提及);但是,我想让事情相对简单一些。另外,我相信如果你不实际使用,一些正则表达式引擎会优化捕获组。@fge我随意更改了一些提示,因为我认为措辞有点漏洞百出。@fge只有极少数能优化它们,因为他们不知道你是否会使用它们稍后从引擎外部访问它们。此外,仅仅在模式周围添加捕获与此特定技术无关,因此我认为更重要的是关注模式内部的优化。
\b\d{1,3}(\.\d{1,3}){3}\b