将正则表达式插入到另一个正则表达式中

时间:2013-05-23 02:28:59

标签: ruby regex string-interpolation

在以下代码中,k2k1的差别不大。也就是说,k2完全相同,只是它是使用插值定义的。 (也就是说,我期望它完全相同;显然从p k2的结果来看,它不是。)

v  = /[aeiouAEIOUäöüÄÖÜ]/                 # vowels
k1 = /[[ßb-zB-Z]&&[^[aeiouAEIOUäöüÄÖÜ]]]/ # consonants defined without interpolation
k2 = /[[ßb-zB-Z]&&[^#{v}]]/               # consonants defined same way, but with interpolation

但如下所示,gsubk1一起使用,而将k2all_chars = "äöüÄÖÜß"<<('a'..'z').to_a.join<<('A'..'Z').to_a.join p all_chars                  # "äöüÄÖÜßabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" p all_chars.gsub( k1 , '_' ) # "äöüÄÖÜ_a___e___i_____o_____u_____A___E___I_____O_____U_____" p all_chars.gsub( k2 , '_' ) # "äöüÄÖÜ_abcdefghijklm_o_____u__x__ABCDEFGHIJKLMNOPQRSTUVWXYZ" p k1                         # /[[ßb-zB-Z]&&[^[aeiouAEIOUäöüÄÖÜ]]]/ p k2                         # /[[ßb-zB-Z]&&[^(?-mix:[aeiouAEIOUäöüÄÖÜ])]]/ 一起使用会以我不理解的方式失败。

(?-mix:...)

为什么不起作用?什么是{{1}}?有没有办法按照我期望的方式完成这项工作?

4 个答案:

答案 0 :(得分:4)

我做的事情如下:

keywords = %w[foo bar]
regex = /\b(?:#{ Regexp.union(keywords).source })\b/i
# => /\b(?:foo|bar)\b/i

当您想要一次测试单个字符串中多个子字符串的出现时,这很有用。

将正则表达式插入字符串不一定正常。默认情况下,当你这样做时,Ruby使用to_s转换模式,这不是我想要的,因为我不想要模式,标志和所有的完整字符串表示。使用source返回我想要的内容:

regex = Regexp.union(keywords)
regex         # => /foo|bar/
regex.inspect # => "/foo|bar/"
regex.to_s    # => "(?-mix:foo|bar)"
regex.source  # => "foo|bar"

答案 1 :(得分:0)

使用字符串来保存这些字符,并根据需要将其插入到正则表达式中。 Ruby试图用(?mix:)来覆盖一些基础,但它并没有预料到正则表达式会进入另一个正则表达式中的字符集。

背景资讯

以下是真正发生的事情:

在许多情况下,如果将正则表达式插入到正则表达式中,这是有道理的。喜欢这个

a = /abc/       #/abc/
b = /#{a}#{a}/  #/(?-mix:abc)(?-mix:abc)/

'hhhhabcabchthth'.gsub(/abcabc/, '_')   # "hhhh_hthth"
'hhhhabcabchthth'.gsub(b, '_')          # "hhhh_hthth"

它按预期工作。整个(?-mix:事件是封装a规则的一种方式,以防b有不同的标志。 a区分大小写,因为这是默认设置。但是,如果b设置为不区分大小写,则a继续匹配之前匹配的唯一方法是使用-i确保区分大小写。冒号后(?-i:)内的任何内容都将与区分大小写匹配。以下

更清楚地说明了这一点
e = /a/i # e is made to be case insensitive with the /i
/#{e}/   # /(?i-mx:a)/

您可以在上面看到,在将e插入某个内容时,您现在拥有(?i-mx:)。现在i位于-的左侧,这意味着它会变为不区分大小写,而不是关闭(暂时),以便e像往常一样匹配。

此外,为了避免搞乱捕获订单,添加(?:以创建一个未捕获的组。所有这一切都是为了让ae变量与您希望它们匹配到一个更大的正则表达式时匹配的粗略尝试。

不幸的是,如果你把它放在一个字符集匹配中,意思是[],这个策略就完全失败了。 [(?-mix:)]现在的解释完全不同了。 [^?-m]表示不在&#34;?&#34;之间的所有内容和&#34; m&#34; (包括),这意味着,例如,字母&#34; c&#34;不再是你的角色集。这意味着&#34; c&#34;如您在示例中所示,不会被下划线替换。你可以看到字母&#34; x&#34;发生同样的事情。它也没有被下划线替换,因为它在否定的字符集中,因此不在匹配的字符中。

Ruby并不打算解析正则表达式来弄清楚你是否正在将正则表达式插入到一个字符集中,即使这样做了,它仍然需要解析{{1变量,以确定它也是一个字符集,因此你真正想要的是从v中的字符集中取出字符并将其与所有其他字符放在那里。

我的建议是,由于v只是一堆字符,你可以将它存储在一个字符串中,并将其插入到正则表达式中的任何字符集中。并且在将来将正则表达式插入正则表达式时要小心。除非你确定要做什么,否则要避免它。

答案 2 :(得分:-2)

我正在使用的答案:

如果您想将some_regex插入另一个regex1.inspect[1...-1],请在#{}内使用v = /[aeiouAEIOUäöüÄÖÜ]/ # vowels k3 = /[[ßb-zB-Z]&&[^#{v.inspect[1...-1]}]]/ # consonants

例如,以我的原始例子为例,这种使用插值定义辅音的方法有效。

.inspect[1...-1]

(我不知道是否有某种内置方法可以为正则表达式完成与.to_s相同的功能。

我很惊讶,"(?-mix:对于正则表达式的作用还不是很明显。

我仍然不确定)" some_regex {{1}}的用途。)

答案 3 :(得分:-3)

您的陈述“k2完全相同,只是使用插值定义”是错误的。

当您插入非字符串的内容(例如正则表达式v)时,会将其转换为带有to_s的字符串。

v = /[aeiouAEIOUäöüÄÖÜ]/
v.to_s # => "(?-mix:[aeiouAEIOUäöüÄÖÜ])"

将其插入k2,从而产生与k1不同的正则表达式。如果您希望k2k1相同,则需要插入字符串:

v = "[aeiouAEIOUäöüÄÖÜ]"