Ruby:布尔型正则表达式方法的正确语法是什么?

24

如何编写一个检查字符串是否匹配正则表达式并返回true或false的方法?

基本思路:

def has_regex?(string)
    pattern = /something/i
    return string =~ pattern
end

使用案例:

if has_regex?("something")
    # woohoo
else
    # nothing found: panic!
end

2
你的代码可以直接运行,所以我不太明白你在问什么。 - sepp2k
哈哈,我的错。我没有正确调试我的代码。谢谢你指出了本应显而易见的问题。 - Marco
1
没有必要定义has_regex?,只需执行if "something" =~ /something/i即可。 - Jonathan Julian
我希望将这个模式放在自己的方法中,因为我要在多个地方重复使用它,并且我想避免声明全局变量。 - Marco
10个回答

46

你在问题中说:

...一个检查字符串模式的方法,并且如果正则表达式匹配,则返回true或false

正如johannes所指出的,String=~会在没有匹配的情况下返回nil,否则返回匹配单词开始的字符串位置。他进一步指出,在Ruby中除了nilfalse外,所有东西都像true一样。这一切都是正确的。

但是,它们不是完全truefalse。因此,最后一步是将值强制转换为Boolean。通过在结果前加双重感叹号,可以返回一个true

def has_regex?(string)
    !!(string =~ /something/i)
end

3
或:!(string !~ /something/i) 的意思是“如果字符串中不包含 'something'(不区分大小写),则返回真”。 - ma11hew28
1
对于最新版本的Ruby,请参考下面的matthew.tuck的回答 - Aaron Thomas

15

你的代码看起来不错,但你可以将其写得更加简短。

String#=~ 的返回值如下:

  • 如果没有匹配成功,则返回nil
  • 匹配成功时返回字符串中匹配单词的起始位置

在Ruby中,除了nilfalse,其他所有值都在条件语句中表现为true,所以你可以直接写成:

if string=~ pattern
  # do something
else
  # panic
end

3
您的答案适用于提供的使用案例,但并没有正确回答问题(这将对来到这里的人很重要)。例如,当将结果分配给ActiveRecord对象时,这非常关键:Foo.new(admin: (role =~ /admin/)).admin返回falserole为"admin"时,因为=〜返回0,而Rails会将其转换为false。只是说一下。 - codener

14

11

要使其返回 true/false,请交换模式和字符串的位置,并使用严格相等运算符 ===。

def has_regex?(string)
    pattern = /something/i
    return pattern === string
end

我绝对需要它返回true布尔值并且四处查找。 实际上这在regexp类文档中有记录 http://www.ruby-doc.org/core-2.1.3/Regexp.html#method-i-3D-3D-3D


这是最佳解决方案,但需要注意的是,当 str 不是 StringSymbol 时,regex === str 返回 false,而其他在此处发布使用 =~ 的解决方案会引发 TypeError - cozyconemotel

9

对于 Ruby >= 2.4 或 Rails,你可以执行以下操作:

 regexp.match?(string)

2
将以下内容添加到String类中,使用起来非常简单:
   class String
      def match?(regex)
          !!self.match(regex)
      end
   end

我把它添加到了Rails的初始化器中(RAILS_ROOT/config/initializers),你可以直接从字符串中调用:

"Something special!".match?(/something/i) #=> true 
"Somethin' special!".match?(/something/i) #=> false 

1

供大家参考,bbatsov的Ruby编码规范不建议使用双感叹号。取而代之的是,检查值不是 nil。如果该值不为nil,则存在。

不要这样做:

def has_regex?(string)
  !!(string =~ /something/i)
end

你总是可以这样做:

def has_regex?(string)
  !(string =~ /something/i).nil?
end

也许可以使用(string =~ /something/i).present?,这样就不必反转它了? - rachel
我更喜欢使用(string =~ /something/i) != nil,因为我觉得它更易读。 - ma11hew28
2
请注意,present?是ActiveSupport方法(即Rails的一部分),如果您只使用常规Ruby,则不可用。 - GMA

1

我没有足够的声望来评论,所以我将回答。

如viljar建议的那样使用 === 是不被建议的Ruby风格指南,并且会导致Rubocop投诉(在默认规则下)。

我发现最易读的方法是:

def match?(string)
  !(string =~ /something/i).nil?
end

0

由于我希望这个功能通用,而不仅仅适用于特定的项目,因此我不想修改环境。

我只需使用正常的match方法的返回值作为条件,就能使它正常工作。在这个示例字符串上测试了正面和负面情况:

irb(main):014:0> if "123".match(/.2./); puts "worked"; end
worked
=> nil
irb(main):015:0> if "123".match(/.3./); puts "worked"; end
=> nil

-3
如果您想将模式放入一个方法中,只需执行以下操作:
def has_my_pattern(st)
    st =~ /pattern/
end

或者,更好的方法是将模式放在类变量中?


11
这并不返回布尔值。@Ryan的回答是正确的。 - Joshua Hoblitt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接