Ruby: 子匹配组在不应该的时候为 nil
Ruby: sub match groups are nil when it should not
我正在尝试获取信用卡号字符串并用星号掩盖中间数字。
我使用正则表达式 /^([\d]{6})([\d]{3,6})([\d]{4})$/
来匹配三个组:
- 前 6 位数字
- 将被混淆的中间数字(3 到 6)
- 最后 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"
我正在尝试获取信用卡号字符串并用星号掩盖中间数字。
我使用正则表达式 /^([\d]{6})([\d]{3,6})([\d]{4})$/
来匹配三个组:
- 前 6 位数字
- 将被混淆的中间数字(3 到 6)
- 最后 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"