如何匹配包含子字符串的模式

时间:2019-03-04 16:56:21

标签: regex ruby

我有这段文字:

Testing some text {{ first_name | mask }} and another {{ city }} and again {{ state | mask_trail }}

我只想匹配包含管道{{}}的{​​{1}}

但是当我做类似的事情

|

text.scan(/({{.*?\|+.*?}})/) 也被匹配

2 个答案:

答案 0 :(得分:2)

使用可以使用此正则表达式,

{{(?:(?!{{).)*\|(?:(?!{{).)*}}

说明:

  • {{-匹配文字{{
  • (?:(?!{{).)*-匹配文字{{(也称为Tempered Greedy Token
  • 除外的任何文本)
  • \|-匹配管道|个字符
  • (?:(?!{{).)*-再次匹配除文字{{之外的所有文本
  • }}-匹配文字}}

Demo 1

此外,如果存在类似的嵌套模式,并且您想匹配最内部的模式,则可以使用此正则表达式,

{{(?:(?!{{|}}).)*\|(?:(?!{{|}}).)*}}

Demo 2

查看此Ruby代码,

re = /{{(?:(?!{{|}}).)*\|(?:(?!{{|}}).)*}}/
str = 'Testing some text{{ {{ first_name | mask }} }} and another {{ city }} and again {{ state | mask_trail }}'

str.scan(re) do |match|
    puts match.to_s
end

输出

{{ first_name | mask }}
{{ state | mask_trail }}

Online Ruby demo

答案 1 :(得分:0)

我假定(部分由于问题的示例而定)匹配将排除以“ {{”开头和以“}}”结尾的字符串,其中包含“ |”,也包含“ {{”。例如,

"{{ a | {{ b }}"

"{{ a | {{ b }} c }}"

要匹配。如果要使它们匹配,则可以使用@WiktorStribiżew在对该问题的评论中建议的正则表达式。

您可以按以下方式获得所需的匹配项。

str = "Testing some text {{ first_name | mask }} and another {{ city }} " +
      "and again {{ state | mask_trail }}"

R = /
    {{         # match '{{'
    ((?!{{).)  # match one character not preceded by '{{'. Save in capture group 1
    *          # perform capture to group 1 zero or more times 
    \|         # match '|'
    \g<1>      # execute subroutine defined by capture group 1
    *          # perform preceding match zero or more times
    }}         # match '}}'
    /x         # free-spacing regex definition mode

或者简而言之

R = /{{((?!{{).)*\|\g<1>*}}/

str.gsub(R).to_a
  #=> ["{{ first_name | mask }}", "{{ state | mask_trail }}"]

我无法使用String#scan,因为我不想返回捕获组的内容。因此,我使用String#gsub而不带任何块返回一个生成匹配项的枚举器,然后将其转换为匹配项数组。 Here是对正则表达式子例程或子表达式的讨论。

我从@Pushpesh的答案中借来了(?!{{).