无法理解为什么我的代码中禁用了Regexp选项

时间:2013-01-19 11:49:42

标签: ruby regex

我刚刚开始玩Ruby,而且我被困在某事上。是 有一些技巧可以修改Regexp对象的casefold attribute 它被实例化了吗?

我尝试过的最好的想法是:

irb(main):001:0> a = Regexp.new('a')
=> /a/
irb(main):002:0> aA = Regexp.new(a.to_s, Regexp::IGNORECASE)
=> /(?-mix:a)/i

但以下似乎都不起作用:

irb(main):003:0> a =~ 'a'
=> 0
irb(main):004:0> a =~ 'A'
=> nil
irb(main):005:0> aA =~ 'a'
=> 0
irb(main):006:0> aA =~ 'A'
=> nil

我不明白的事情发生在这里。 “我”在哪里上线 8?

irb(main):07:0> aA = Regexp.new(a.to_s, Regexp::IGNORECASE)
=> /(?-mix:a)/i
irb(main):08:0> aA.to_s
=> "(?-mix:a)"
irb(main):09:0>

我使用的是Ruby 1.9.3。

我也无法理解以下代码:为什么要返回false

/(?i:a)/.casefold?      #=> false

3 个答案:

答案 0 :(得分:2)

由于to_s的结果只是正则表达式字符串本身 - 没有分隔符或外部标志 - 标志被转换为(?i:...)语法,该语法在表达式本身内暂时设置或清除它们。这样,您就可以通过一个匹配相同字符串的简单Regexp调用来恢复Regexp.new(s)个对象。

不幸的是,换行包括显式清除对象上 设置的标志。因此,您的第一个正则表达式会被归结为(?:-i...)之间的某些内容 - 也就是说,casefold选项在括号之间明确地转为 off 。为对象重新打开它没有任何效果。

您可以使用a.source代替a.to_s来获取原始表达式,而不使用标记设置:

irb(main):001:0> a=/a/
=> /a/
irb(main):002:0> aA = Regexp.new(a.source, Regexp::IGNORECASE)
=> /a/i
irb(main):003:0> a =~ 'a'
=> 0
irb(main):004:0> a =~ 'A'
=> nil
irb(main):005:0> aA =~ 'a'
=> 0
irb(main):006:0> aA =~ 'A'
=> 0

答案 1 :(得分:2)

正如您的控制台输出所示,a.to_s包含区分大小写作为子表达式的选项,因此aA被定义为

/(?-mix:a)/i

所以你要求ruby提供一个不区分大小写的正则表达式,但在这种情况下,唯一不敏感的regexp是一个用于打开区分大小写时的组,因此净效果是'a'匹配区别敏感

答案 2 :(得分:1)

正如Frederick已经解释的那样,在正则表达式上调用to_s会在其周围添加修饰符,以确保保留其区分大小写等属性。因此,如果将区分大小写的正则表达式插入到不区分大小写的正则表达式中,则插入的部分仍将区分大小写。同样,如果第一个参数是正则表达式或者在一个参数上调用to_s的结果,则给予Regexp.new的修饰符将不起作用。

要解决此问题,请在正则表达式而不是source上调用to_s。与to_s不同,source只返回正则表达式的来源而不添加任何内容:

aA = Regexp.new(a.source, Regexp::IGNORECASE)
  

我也无法理解下面的代码:为什么返回false:

/(?i:a)/.casefold? 

因为(?i:...)在本地设置i标志,而不是全局。它仅适用于括号内的正则表达式部分,而不是整个正则表达式。当然,在这种情况下,整个正则表达式都在括号内,但就casefold?这样的方法而言,这并不重要。