首页 > 解决方案 > 一种仅在输入唯一短语时才执行块的方法

问题描述

例如我在一个程序中有两个命令:

elsif @@content.downcase.include? "!roll"
      randomRoll = rand(100)
      puts("You rolled a #{add_comma_to_numbers(randomRoll.to_s)} (1-100)")

elsif @@content.downcase.include? "!roll1m"
      randomRoll = rand(1000000)
      puts("You rolled a #{add_comma_to_numbers(randomRoll.to_s)} (1-1m)")

因为 !roll1m 与 !roll 具有相同的前缀,所以它们都在输入 !roll 时执行,我只希望执行最前面的那个。除了包含之外,也许还有另一种方法可以使用?

我曾想过只是简单地翻转两者,但这只是一个临时修复。任何建议都会有所帮助

标签: ruby

解决方案


你可以这样做:

r = /!roll\b/

其内容为“匹配字符串 '!roll' 后跟一个单词中断”。

'!roll'.match?(r)
  #=> true
'I am on a !roll today'.match?(r)
  #=> true
'!roll1m'.match?(r)
  #=> false

此外,如果我们希望匹配"tootsie !roll"但不匹配,"tootsie!roll"我们可以使用以下任一正则表达式:

r = /(?<=\A|\W)!roll\b/
r = /(?<!\w)!roll\b/

(?<=\A|\W),一个正向的后视( (?<=...)),要求字符串"!roll"紧跟在字符串的开头 ( \A)( |) 前面是一个非单词字符 ( \W)。

(?<!\w),一个否定的lookbehind ( (?<!...)),要求字符串"!roll"不能紧跟单词字符( \w) 之前。

\b要求'!roll'后面跟一个单词 break,意思'!roll'是后面必须跟一个非单词字符或者在字符串的末尾。

两者都返回以下内容:

"tootsie !roll".match?(r) #=> true
"tootsie!roll".match?(r)  #=> false

我最初期望我可以使用正则表达式

r = /\b!roll\b/

但正如我在评论中提醒的那样,断字字符\b, 要求一侧有一个单词字符,而另一侧没有一个单词字符。这包括一个单词字符之前和之后没有字符或单词字符之后并且之前没有字符。1

例如,

r = /\b!roll\b/
"!roll".match?(r) 
  #=> false (\W ('!') after \b but no \w before '!')
"tootsie!roll".match(r)
  #=> true  (\w before \b, \W ('!') after \b)
"tootsie !roll".match(r)
  #=> false (\W before and after \b)

1. Regexp (v2.7.0)的文档中没有明确说明,“ \b- 括号外时匹配单词边界;括号内时退格 (0x08)”。


推荐阅读