Ruby: 子匹配组在不应该的时候为 nil

Ruby: sub match groups are nil when it should not

我正在尝试获取信用卡号字符串并用星号掩盖中间数字。 我使用正则表达式 /^([\d]{6})([\d]{3,6})([\d]{4})$/ 来匹配三个组:

正如您从我下面的控制台中看到的那样,gsub 匹配组最初是 nil,直到我在替换属性中使用文字字符串。然后当我尝试 运行 初始调用时,它起作用了。

2.0.0-p598 :001 > c = "5454545454545454"
 => "5454545454545454"

2.0.0-p598 :002 > c.gsub(/^([\d]{6})([\d]{3,6})([\d]{4})$/,  + '*' * .size + )
NoMethodError: undefined method `size' for nil:NilClass
    from (irb):2
    from /Users/guilherme/.rvm/rubies/ruby-2.0.0-p598/bin/irb:12:in `<main>'

2.0.0-p598 :003 > c.gsub(/^([\d]{6})([\d]{3,6})([\d]{4})$/, "anything")
 => "anything"

2.0.0-p598 :004 > c.gsub(/^([\d]{6})([\d]{3,6})([\d]{4})$/,  + '*' * .size + )
 => "545454******5454"

为什么会这样?这是一个错误吗?如何解决这个问题并让它在第一次尝试时起作用?

对于像这个这样的更高级的替换,您应该使用 gsub 的块形式。魔术变量在那里有值。

s = '1234567890123456'
rgx = /^([\d]{6})([\d]{3,6})([\d]{4})$/

s2 = s.gsub(rgx) do
   + '*' * .size + 
end

s2 # => "123456******3456"

(在非块形式中,匹配可用 </code>、<code> 等。适用于简单替换,但您不能对它们调用 .size,等等)

魔术变量在参数形式中不可用,因为参数在 方法调用之前计算。因此,尚未设置变量。如果你两次调用这样的方法,第二次你会从第一次得到匹配。

或者,您可以避免所有这些正则表达式巫术,直接屏蔽字符

s3 = s.dup # don't touch the original string
s3[6...-4] = '*' * (s.length - 4 - 6) # string of asterisks of variable length
s3  # => "123456******3456"

如果您可以替换数字中的字符,我肯定会采用 Sergio Tulentsev 建议的解决方案。如果不是:

c[0..5] + '*' * (c.size - 10) + c[-4..-1]

您可以在没有捕获组或块的情况下使用 sub,如下所示:

r = /
    (?<=^.{6}) # match any 6 chars at beginning of string in a positive lookbehind
    .+         # match any number of any character, greedily
    (?=.{4}$)  # match any 4 chars at end of string in a positive lookahead
    /x         # extended option

s.sub(r, '*'*(s.size-10))
  #=> "123456******3456" 

您可以在不将“*”乘以字符串大小的情况下执行此操作。

'1234123412341234'.gsub(/(?<=......).(?=....)/, '*')

=> "123412******1234"