为什么正则表达式不能匹配@符号?

时间:2014-04-09 01:31:09

标签: ruby-on-rails ruby regex

对于字符串Be there @ six.

为什么这样做:

str.gsub! /\bsix\b/i, "seven"

但是尝试替换@符号并不匹配:

str.gsub! /\b@\b/i, "at"

逃避它似乎也无效:

str.gsub! /\b\@\b/i, "at"

2 个答案:

答案 0 :(得分:4)

这取决于\b的解释方式。 \b是一个“字边界”,如果\b前面跟着字符,则会发生零长度匹配。单词字符仅限于[A-Za-z0-9_]以及其他一些内容,但@不是单词字符,因此\b在它之前(以及在空格之后)将不匹配。空间本身不是边界。

More about word boundaries...

如果您需要将@替换为周围的空格,则可以在\b之后捕获它并使用反向引用。对于零个或多个空格字符,这会使用\s*捕获前面的空格。

str.gsub! /\b(\s*)@(\s*)\b/i, "\\1at\\2"
=> "Be there at six"

或者坚持使用空格,请使用\s+代替\s*

str = "Be there @ six."
str.gsub! /\b(\s+)@(\s+)\b/i, "\\1at\\2"
=> "Be there at six."

# No match without whitespace...
str = "Be there@six."
str.gsub! /\b(\s+)@(\s+)\b/i, "\\1at\\2"
=> nil

此时,我们开始通过强制使用\b来引入冗余。使用/(\w+\s+)@(\s+\w+)/可以轻松完成,\b匹配\w字符后跟\s空格。

评论后更新:

如果您想将@视为可能出现在开头或结尾的“字”,或者以空格为界,则可以使用\W来匹配“非字”字符,与^$锚点组合使用“或”管道|

# Replace @ at the start, middle, before punctuation
str = "@ Be there @ six @."
str.gsub! /(^|\W+)@(\W+|$)/, '\\1at\\2'
=> "at Be there at six at."

(^|\W+)匹配字符串开头的^或非字字符序列(如空格或标点符号)。 (\W+|$)类似,但可以匹配字符串$的结尾。

答案 1 :(得分:1)

\b匹配单词边界,这是单词字符紧挨着非单词字符的位置。在您的字符串中,@每边都有一个空格,@或空格都不是单词字符,因此没有匹配。

比较

'be there @ six'.gsub /\b@\b/, 'at'

产生

'be there @ six'

(即没有变化)

'be there@six'.gsub /\b@\b/, 'at' # no spaces around @

产生

"be thereatsix"

另外

'be there @ six'.gsub /@/, 'at' # no word boundaries in regex

产生

"be there at six"