【问题标题】:is there a Ruby way to substitute the last four digits of a string, excluding spaces?有没有一种 Ruby 方法可以替换字符串的最后四位数字,不包括空格?
【发布时间】:2020-01-19 16:08:03
【问题描述】:

我必须找到一种方法来匿名化最后四个数字字符。呈现一个电话号码字符串,如“+36 6 41 88 75 22”(或任何其他格式,如“+36641887522”或+36 6 418 875 22 等),我希望我的代码输出“+36 6 41 88 XX XX"。

phoneNumber = "+36 6 41 88 75 22" 我找到的最接近我想要的选择的正则表达式是: /\d.{4}$/ 这很方便,因为lastFour = phone.scan(/\d.{4}$/).join 等于“75 22”,包括空格。

现在我想用“X”替换所有数字(不是空格!),但是

phoneNumber.gsub(/\d.{4}$/, "X")

输出“+36 6 41 88 X”,我希望我的代码输出“+36 6 41 88 XX XX”。

我也尝试过以下繁琐的解决方案:

phoneNumber = "+36 6 41 88 75 22"
def anonymizer(phone)
    lastFour = phone.scan(/\d.{4}$/).join
    anonFour = lastFour.chars
    anonFour.each do |digit|
        digit.gsub(/[0-9]/, "X")
    end
    puts "attempted transform #{anonFour}"
    phone.gsub(lastFour, anonFour.join)
end


phoneyNumber = anonymizer(phoneNumber)
puts phoneyNumber 

无济于事,因为它按原样返回数字(“+36 6 41 88 75 22”而不是“+36 6 41 88 XX XX”)

【问题讨论】:

  • 您需要澄清(通过编辑您的问题)电话号码可能具有的模式。你举一个例子,最后六个字符是'dd dd',其中'd'代表一个数字。如果您只对该模式感兴趣,那么解决方案很简单。我希望最后四位数字的其他模式是可能的(例如,'d d dd' 或 'd, ext. ddd'),因为这将使它成为一个更有趣的问题。如果第二种解释是可能的,那么给出第二个例子就足够了,它至少在最后四位数字上具有不同的模式。
  • 是的,我没有指定我的解决方案需要灵活。它必须适用于 +12 3 456 789 01 和 123 456 7890 和所有其他格式
  • Both my solutions 处理您正确指定的格式。

标签: regex ruby string substitution


【解决方案1】:

你可以使用

phoneNumber = phoneNumber.gsub(/\d(?=(?:\D*\d){0,3}\D*\z)/, 'X')

请参阅 regex demoonline Ruby demo

详情

  • \d - 一个数字...
  • (?=(?:\D*\d){0,3}\D*\z) - 紧随其后的是
    • (?:\D*\d){0,3} - 0 到 3 次连续出现
      • \D* - 0+ 个非数字字符
      • \d - 一个数字
    • \D* - 0+ 个非数字字符
    • \z - 字符串结尾($ 匹配 Ruby 正则表达式中的行尾)。

另一个想法:将最后四位数字与数字以外的任何字符匹配,然后将这些数字替换为X

phoneNumber.gsub(/(?:\d\D*){4}\z/) { $~[0].gsub(/\d/, 'X') }

this Ruby demo

这里,(?:\d\D*){4}\z 匹配四个连续出现的数字和字符串末尾的任何 0+ 非数字字符,gsub 块中的 $~[0] 表示 .gsub(/\d/, 'X') 替换的整个匹配值每个数字都带有X

【讨论】:

  • 很好地解释了正则表达式,不幸的是我的问题对于电话号码字符串的许多可能格式并不完全清楚,所以这实际上只涵盖了一些可能性。
  • @WildWilyWilly 我的代码没有涵盖哪些字符串?它涵盖了所有可能性,甚至是数字之间的标点符号。
  • 老兄,很抱歉,虽然我的问题还没有完全展开,但你绝对是对的。
  • 我的错,我应该在我的代码上测试这个而不是我使用的糟糕的正则表达式应用程序
【解决方案2】:

如果您的字符串仅包含以“dd dd”结尾的电话号码,其中d 是一个数字,则不需要正则表达式:

'+36 6 41 88 75 22'[0..-6] + 'XX XX'
  #=> "+36 6 41 88 XX XX" 

然而,我假设对“最后四个数字字符”的更有趣的解释是,连续的数字对可以分隔零个或多个非数字。在这种情况下,以下是进行所需替换的简单方法。

def sub_last4(str)
  n = str.count('0-9')
  str.gsub(/\d/) { |s| (n -= 1) <= 3 ? 'X' : s }
end

sub_last4 '+36 6 41 88 75 22'
  #=> "+36 6 41 88 XX XX" 
sub_last4 '+36 6 41 88 7522'
  #=> "+36 6 41 88 XXXX"
sub_last4 '+36 6 how 41 8 now 8 75 2 brown 5 cow'
  #=> "+36 6 how 41 8 now 8 XX X brown X cow"
sub_last4 'SY-0-6447'
  #=> "SY-0-XXXX"

这是第二种方法。

def sub_last4(str)
  4.times.each_with_object(str.dup) { |_,s|
    s[s.rindex(/\d/)] = 'X' }
end

【讨论】:

  • 我需要它来处理各种电话号码格式,无论是 12 23 34 45 56、122 334 4556 还是 1223344556,所以第一个解决方案不是一个选项。第二个成功了!
  • 第一个解决方案成功了,我一直在努力更好地理解这个单行的语法,``` { |s| (n -= 1)
  • gsub 将每个匹配的一位数字传递给其块,将块变量 s 设置为等于该匹配。该块计算将替换s 的字符串。该块相当于{ |s| n -= 1; n &lt;= 3 ? 'X' : s }n 首先减少 1,然后如果是 n &lt;= 3,则块返回 ’X’,否则返回 s。在后一种情况下,由于s被替换为自身,因此数字不会被修改。
  • str.count('0123456789') 可以替换为str.count('0-9')
  • @3limin4t0r,这很有趣。我做了一个编辑。我不知道String#count 可以采取的各种论点。读者示例:str = "my dog has fleas"; str.count 'sadh', '^g-i' #=&gt; 5,因为它正在计算字符串 'sadh' 和字符串 'ghi' 中的 not 中的字符数。那将是字符串'sad'中的字母,其中str包含2个's',2个'a'和1个'd',总共5...
【解决方案3】:

您可以反转字符串,然后用'X' 替换单个数字四次。

phone_number = '+36 6 41 88 75 22'

phone_number.reverse!
4.times { phone_number.sub!(/\d/, 'X') }
phone_number.reverse!

phone_number
#=> "+36 6 41 88 XX XX"

请注意,我在这里使用变异方法,如果您不想改变原始方法,请将第一个 phone_number.reverse! 替换为 phone_number = phone_number.reverse。这将创建一个可以安全地被其他变异方法操作的新字符串。

您可以根据喜好将phone_number.sub!(/\d/, 'X') 替换为phone_number[/\d/] = 'X'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-19
    • 2019-12-27
    • 2010-12-05
    • 2018-09-17
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    相关资源
    最近更新 更多