让我们有一个文本,我们希望在双引号之间匹配所有字符串; 但在这些双引号内,可以引用双引号.例:
"He said \"Hello\" to me for the first time"
Run Code Online (Sandbox Code Playgroud)
使用正则表达式,您如何有效地匹配它?
fge*_*fge 14
匹配此类输入的一种非常有效的解决方案是使用该normal* (special normal*)*模式; 这个名字引自Jeffrey Friedl的精彩书籍,掌握正则表达式.
它是一种通常用于匹配由常规条目(正常部分)和中间分隔符(特殊部分)组成的输入的模式.
请注意,像所有正则表达式一样,它应该在没有更好的选择时使用; 虽然可以使用此模式来解析CSV数据,例如,如果您使用Java,您最好使用OpenCSV.
另请注意,虽然模式名称中的量词是星号(即零或更多),但您可以根据需要改变它们.
让我们再看一遍上面的例子; 请注意,此文本示例可能位于您输入的任何位置:
"He said \"Hello\" to me for the first time"
Run Code Online (Sandbox Code Playgroud)
无论你怎么努力,没有多少"点加上贪婪/懒惰量词"的魔法会帮助你解决它.相反,将引号之间的输入分类为正常和特殊:
[^\\"];\\".将其替换为normal* (special normal*)*模式,这给出了以下正则表达式:
[^\\"]*(\\"[^\\"]*)*
Run Code Online (Sandbox Code Playgroud)
添加双引号以匹配全文可以得到最终的正则表达式:
"[^\\"]*(\\"[^\\"]*)*"
Run Code Online (Sandbox Code Playgroud)
您会注意到这也将匹配空引用的字符串.
在这里,我们将不得不在量词上使用变量,因为:
为简单起见,我们还假设只允许使用小写的ASCII字母.
样本输入:
the-word-to-match
Run Code Online (Sandbox Code Playgroud)
让我们再次分解为正常和特殊:
[a-z];-该模式的规范形式将是:
[a-z]*(-[a-z]*)*
Run Code Online (Sandbox Code Playgroud)
但正如我们所说:
*应该成为+;*应该成为+.我们最终得到:
[a-z]+(-[a-z]+)*
Run Code Online (Sandbox Code Playgroud)
在它周围添加单词锚点以获得最终结果:
\b[a-z]+(-[a-z]+)*\b
Run Code Online (Sandbox Code Playgroud)
上面的例子把自己限制替换*用+,当然,如你所愿,你可以有很多变化.一个超经典的例子是IP地址:
\d{1,3}),\.),normal只出现一次,因此没有量词,normal里面(special normal*)也只出现一次,因此没有量词,(special normal*)部分恰好出现了三次{3}.这给出了expresison(用词锚装饰):
\b\d{1,3}(\.\d{1,3}){3}\b
Run Code Online (Sandbox Code Playgroud)
这种模式的灵活性使其成为正则表达式工具箱中最有用的工具之一.虽然存在许多问题,如果存在库,则不应使用正则表达式,在某些情况下,必须使用正则表达式.一旦你练习了一下,这将成为你最好的朋友之一!
(special normal*)部分); 因此,建议您使用非捕获组.例如,"[^\\"]*(?:\\"[^\\"]*)*"用于引用的字符串.事实上,如果你想要它,在这种情况下捕获几乎永远不会导致所需的结果,因为重复一个捕获组只会给你最后一次捕获(所有先前的重复将被覆盖),除非你在这个模式中使用.净.(谢谢@ohaal)