如何屏蔽字符串中除了最后四个字符之外的所有字符

时间:2017-03-21 21:28:12

标签: ruby

我一直在尝试编码练习,以掩盖除了输入的最后四位数或字符之外的所有数字。

我认为我的解决方案有效但看起来有点笨拙。有没有人有关于如何重构它的想法?

这是我的代码:

def mask(string)
  z = string.to_s.length

  if z <= 4
    return string
  elsif z > 4
    array = []
    string1 = string.to_s.chars

    string1[0..((z-1)-4)].each do |s|
      array << "#"
    end

    array << string1[(z-4)..(z-1)]

    puts array.join(", ").delete(", ").inspect     
  end
end

6 个答案:

答案 0 :(得分:7)

积极向前看

positive lookahead让它变得非常简单。如果任何字符后跟至少4个字符,则会被替换:

"654321".gsub(/.(?=.{4})/,'#')
# "##4321"

以下是正则表达式的描述:

r = /
     .        # Just one character
     (?=      # which must be followed by
        .{4}  # 4 characters
     )        #
    /x        # free-spacing mode, allows comments inside regex

请注意,正则表达式一次只匹配一个字符,即使每次匹配最多需要检查5个字符:

"654321".scan(r)
# => ["6", "5"]

/(.)..../不起作用,因为每次迭代会消耗5个字符:

"654321".scan(/(.)..../)
# => [["6"]]
"abcdefghij".scan(/(.)..../)
# => [["a"], ["f"]]

如果要参数化未屏蔽字符串的长度,可以使用variable interpolation

all_but = 4
/.(?=.{#{all_but}})/
# => /.(?=.{4})/

代码

将其打包成一个方法,它变为:

def mask(string, all_but = 4, char = '#')
  string.gsub(/.(?=.{#{all_but}})/, char)
end

p mask('testabcdef')
# '######cdef'
p mask('1234')
# '1234'
p mask('123')
# '123'
p mask('x')
# 'x'

您也可以将其改为句子:

def mask(string, all_but = 4, char = '#')
  string.gsub(/\w(?=\w{#{all_but}})/, char)
end

p mask('It even works for multiple words')
# "It even #orks for ####iple #ords"

关于您的代码的一些注意事项

string.to_s

在编程中命名是非常重要的,特别是在动态语言中。

string.to_s

如果string确实是一个字符串,则没有任何理由可以调用to_s

如果string不是字符串,您应该在to_s之前致电gsub,但也应该将string重命名为更好的说明:

object.to_s
array.to_s
whatever.to_s

加入

puts array.join(", ").delete(", ").inspect

你想做什么?您可以使用join

[1,2,[3,4]].join(", ").delete(", ")
# "1234"
[1,2,[3,4]].join
# "1234"

删除

请注意.delete(", ")以任何顺序删除每个逗号和每个空格。它不仅删除", "子串:

",a b,,,   cc".delete(', ')
# "abcc"
["1,2", "3,4"].join(', ').delete(', ')
# "1234"

答案 1 :(得分:3)

Ruby使得这类事情变得非常简单:

class String
  def asteriskify(tail = 4, char = '#')
    if (length <= tail)
      self
    else
      char * (length - tail) + self[-tail, tail]
    end
  end
end

然后你可以像这样申请:

"moo".asteriskify
# => "moo"
"testing".asteriskify
# => "###ting"
"password".asteriskify(5, '*')
# => "***sword"

答案 2 :(得分:2)

试试这个

def mask(string)
  string[0..-5] = '#' * (string.length - 4)
  string
end

mask("12345678")
 => "####5678" 

答案 3 :(得分:1)

我也会在此主题中添加我的解决方案:)

def mask(str)
  str.match(/(.*)(.{4})/)  
  '#' * ($1 || '').size + ($2 || str)  
end  

mask('abcdef') # => "##cdef"
mask('x') # => "x"

答案 4 :(得分:1)

我提供此解决方案主要是为了提醒读者https://docs.microsoft.com/en-us/azure/application-insights/app-insights-asp-net-dependencies没有块返回枚举器。

def mask(str, nbr_unmasked, mask_char)
  str.gsub(/./).with_index { |s,i| i < str.size-nbr_unmasked ? mask_char : s }
end

mask("abcdef", 4, '#')
  #=> "##cdef" 
mask("abcdef", 99, '#')
  #=> "######" 

答案 5 :(得分:0)

尝试使用tap

def mask_string(str)
  str.tap { |p| p[0...-4] = '#' * (p[0...-4].length) } if str.length > 4
  str
end

mask_string('ABCDEF') # => ##CDEF
mask_string('AA') # => AA
mask_string('S') # => 'S'