Reputation: 159
Given any email address I would like to leave only the first and last two characters and input 4 asterisks to the left and right of @ character.
The best way to explain are examples:
[email protected]
changed to lo****@****om
[email protected]
changed fo****@****de
How to do it with gsub?
Upvotes: 1
Views: 3478
Reputation: 166
I have a solution which doesn't fully solve your problem but it's pretty flexible and I think it's worth it to share it for anyone else looking for similar solutions.
module CoreExtensions
module String
module MaskChars
def mask_chars(except_first_n: 1, except_last_n: 2, mask_with: '*')
if except_first_n.zero? && except_last_n.zero?
raise ArgumentError, "except_first_n and except_last_n can't both be zero"
end
if length < (except_first_n + except_last_n)
raise ArgumentError, "String '#{self}' must be at least #{except_first_n}"\
" (except_first_n) #{except_last_n} (except_last_n) ="\
" #{except_first_n + except_last_n} characters long"
end
sub(
/\A(.{#{except_first_n}})(.*)(.{#{except_last_n}})\z/,
'\1' + (mask_with * (length - (except_first_n + except_last_n))) + '\3'
)
end
end
end
end
Let me explain the regex in /\A(.{#{except_first_n}})(.*)(.{#{except_last_n}})\z/
\A
- start of string(.#{except_first_n})
or (.{1})
Group 1: first n
chars. Default value of except_first_n
is 1
(.*)
Group 2 capturing any 0+ chars as many as possible before the last n
characters(.#{except_last_n})
or (.{2})
Group 3: last n
chars. Default value of except_last_n
is 2
\z
- end of stringLet me explain what's happening in '\1' + (mask_with * (length - (except_first_n + except_last_n))) + '\3'
We are substituting the string with group 1 (\1
) at the start, it'll contain characters equalling except_first_n
argument's value. We are not gonna use group 2, we need to replace group 2 with the character from mask_with
argument, to calculate the amount of times we need to add mask_with
character, we use this formula length - (except_first_n + except_last_n)
(total length of the string minus the sum value of except_first_n
and except_last_n
. This will ensure that we have the exact number of mask_with
characters between the except_first_n
and the except_last_n
characters).
Then I created an initializer file config/initializers/core_extensions.rb with this line:
String.include CoreExtensions::String::MaskChars
It will add mask_chars
as an instance method to the String class available to all strings.
It should work like this:
account = "123456789101112"
=> "123456789101112"
account.mask_chars
=> "1************12"
account.mask_chars(except_first_n: 3, except_last_n: 4, mask_with: '#')
=> "123########1112"
I think this is a pretty useful method which can be useful in many scenarios and very flexible too.
Upvotes: 0
Reputation: 626748
**If you want to mask with a fixed number of *
symbols, you may yse
'[email protected]'.sub(/\A(..).*@.*(..)\z/, '\1****@****\2')
# => lo****@****om
See the Ruby demo.
Here,
\A
- start of string anchor (..)
- Group 1: first 2 chars.*@.*
- any 0+ chars other than line break chars as many as possible up to the last @
followed with another set of 0+ chars other than line break ones(..)
- Group 2: last 2 chars\z
- end of string.The \1
in the replacment string refers to the value kept in Group 1, and \2
references the value in Group 2.
If you want to mask existing chars while keeping their number, you might consider an approach to capture the parts of the string you need to keep or process, and manipulate the captures inside a sub
block:
'[email protected]'.sub(/\A(..)(.*)@(.*)(..)\z/) {
$1 + "*"*$2.length + "@" + "*"*$3.length + $4
}
# => lo*********@*******om
See the Ruby demo
Details
\A
- start of string(..)
- Group 1 capturing any 2 chars(.*)
- Group 2 capturing any 0+ chars as many as possible up to the last....@
- @
char(.*)
- Group 3 capturing any 0+ chars as many as possible up to the(..)
- Group 4: last two chars\z
- end of string.Note that inside the block, $1
contains Group 1 value, $2
holds Group 2 value, and so on.
Upvotes: 6
Reputation: 392
Using gsub
with look-ahead and look-behind regex patterns:
'[email protected]'.gsub(/(?<=.{2}).*@.*(?=\S{2})/, '****@****')
=> "lo****@****om"
Using plain ruby:
str.first(2) + '****@****' + str.last(2)
=> "lo****@****om"
Upvotes: 2