2

在下面的代码中,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

但如下所示,使用gsubwithk1有效,而使用 withk2以我不理解的方式失败。

all_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:...)?有没有办法按照我期望的方式完成这项工作?

4

4 回答 4

5

我做的事情是:

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"
于 2013-05-23T04:09:15.940 回答
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]表示不在“?”之间的所有内容 和“m”(包括),这意味着,例如,字母“c”不再在您的字符集中。这意味着正如您在示例中看到的那样,“c”不会被下划线替换。你可以看到字母“x”发生了同样的事情。它也不会被下划线替换,因为它在否定字符集中,因此不在匹配的字符中。

Ruby 不会费心去解析正则表达式来确定你正在将正则表达式插入到字符集中,即使这样做了,它仍然需要解析出v变量来确定它也是一个字符集,因此您真正想要的就是从字符集中取出字符v并将它们与所有其他字符一起放在那里。

我的建议是,既然aeiouAEIOUäöüÄÖÜ只是一堆字符,你可以将它存储在一个字符串中,并将其插入到正则表达式中的任何字符集中。并且在将来将正则表达式插入正则表达式时要小心。避免它,除非你真的确定它会做什么。

于 2017-09-29T17:21:15.873 回答
-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)"的用途。)

于 2013-05-23T03:58:43.217 回答
-3

您的陈述“k2除了使用插值定义之外完全相同”是错误的。

当您插入不是字符串的内容时,例如 regex v,它会被转换为带有to_s.

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

这被插入到k2中,从而产生与 不同的正则表达式k1。如果你想k2和 一样k1,你需要插入一个字符串:

v = "[aeiouAEIOUäöüÄÖÜ]"
于 2013-05-23T02:50:07.620 回答