14~16桁に対応して、数字の間にセパレータが含まれるのも考えると、こんな感じになった。
regexp = /\d(?=(\D*\d){4})/
%w(
1234567890123456
123456789012345
12345678901234
1234-5678-9012-3456
1234-5678-9012-345
1234-5678-9012-34
1234\ 5678\ 9012\ 3456
1234\ 5678\ 9012\ 345
1234\ 5678\ 9012\ 34
).each { |number| puts number + ' => ' + number.gsub(regexp, '*') }
#=>
# 1234567890123456 => ************3456
# 123456789012345 => ***********2345
# 12345678901234 => **********1234
# 1234-5678-9012-3456 => ****-****-****-3456
# 1234-5678-9012-345 => ****-****-***2-345
# 1234-5678-9012-34 => ****-****-**12-34
# 1234 5678 9012 3456 => **** **** **** 3456
# 1234 5678 9012 345 => **** **** ***2 345
# 1234 5678 9012 34 => **** **** **12 34
\d(?=(\D*\d){4})
は 「その文字以降に数字が4つ以上現れる」数字にマッチするので、その数字をString#gsub
で'*'
に置き換えている。
Rubular
こういうのを考える時はRubular使うと便利。
Rubular: a Ruby regular expression editor and tester
http://rubular.com/
permalinkも生成できるので、複雑な正規表現を書いた時はソースコードのコメントにpermalinkを貼ったりしてもいいかもしれない。