Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

masking SSN to last four

by Anonymous Monk
on Aug 09, 2019 at 00:07 UTC ( [id://11104203]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

# Trying to mask the last four of a string where search has # SSN=123-12-1234 # change to # SSN=XXX-XX-1234

Replies are listed 'Best First'.
Re: masking SSN to last four
by davido (Cardinal) on Aug 09, 2019 at 02:18 UTC

    sub ss_last_4 { my $n = shift; $n =~ tr/0-9//cd; # We can only work with numeric digits. # There are some basic constraints we can assure are met. die "$n cannot be a social security number.\n" if 9 != length($n) || $n =~ m/(^0{3})|(^\d{3}0{2})|(0{4}$)/ # A grouping of +zeros represents a fictitious SS number. || substr($n,0,3) == 666 # Prefixes that +== 666, or are >= 900 and <= 999 are reserved. || substr($n,0,3) >= 900; # Still alive, return the last four. return substr($n,-4,4); }

    Just today a website rejected my phone number because I entered it without hyphens. Amazing how something that is really only a formatting convention gets baked into validation. Ok, for socials hyphens are supposed to be a requirement, but how many times have you visited websites where the hyphen handling is wonky? IMO it's easier to filter them out on input, and re-apply them on output.

    Don't be tempted to use SSN::Validate (which could easily return the last four for you); in 2011 the US government made changes to how the first three digits are allocated, and the changes broke assumptions made in that module.


    Dave

Re: masking SSN to last four
by AnomalousMonk (Archbishop) on Aug 09, 2019 at 02:34 UTC

    For strings with multiple SSN-like sub-strings, this works for Perl versions 5.14+:

    c:\@Work\Perl\monks>perl use 5.014; # needed for s///ubstitution /r modifier use warnings; use strict; use Test::More 'no_plan'; use Test::NoWarnings; # use Data::Dump qw(dd pp); # for debug my $rx_semi_strict_ssn = qr{ (?> (?<! \d) \d{3} (\D?) \d{2} \g-1 \d{4} (?! \d)) }xms; my @TESTS = ( 'masking valid ssns', [ '# SSN=123-12-1234 987.65.4321' => '# SSN=XXX-XX-1234 XXX.XX.4321' ], [ '123456789 123 45 6789' => 'XXXXX6789 XXX XX 6789' ], 'no masking (no valid ssns)', [ '12345678 12345123451 123-456789' => '12345678 12345123451 123-456789' ], [ '12-3-45-6789 12345 6789 123-45.6789' => '12-3-45-6789 12345 6789 123-45.6789' ], ); VECTOR: for my $ar_vector (@TESTS) { if (not ref $ar_vector) { note $ar_vector; next VECTOR; } my ($str, $expected) = @$ar_vector; my $got = $str; $got =~ s{ ($rx_semi_strict_ssn) } { $^N =~ s{ (?! \d{1,4} \z) \d }{X}xmsgr }xmsge; ok $got eq $expected, qq{'$str' -> '$expected'}; } # end for VECTOR done_testing; exit; __END__ # masking valid ssns ok 1 - '\# SSN=123-12-1234 987.65.4321' -> '\# SSN=XXX-XX-1234 XXX.XX. +4321' ok 2 - '123456789 123 45 6789' -> 'XXXXX6789 XXX XX 6789' # no masking (no valid ssns) ok 3 - '12345678 12345123451 123-456789' -> '12345678 12345123451 123- +456789' ok 4 - '12-3-45-6789 12345 6789 123-45.6789' -> '12-3-45-6789 12345 67 +89 123-45.6789' 1..4 ok 5 - no warnings 1..5
    (A fairly simple change can accommodate this code to pre-5.14 Perl versions — /r modifier not supported; let me know if it's needed.)


    Give a man a fish:  <%-{-{-{-<

Re: masking SSN to last four
by AnomalousMonk (Archbishop) on Aug 09, 2019 at 00:48 UTC

    TIMTOADY:

    c:\@Work\Perl\monks>perl -wMstrict -le "my $ssn = '# SSN=123-12-1234'; print qq{'$ssn'}; ;; $ssn =~ s{ (?! \d{1,4} \z) \d }{X}xmsg; print qq{'$ssn'}; " '# SSN=123-12-1234' '# SSN=XXX-XX-1234'


    Give a man a fish:  <%-{-{-{-<

Re: masking SSN to last four
by atcroft (Abbot) on Aug 09, 2019 at 01:03 UTC

    Another possible approach to doing what you request:

    $ # Code (1-liner, expanded) and example output, $ # handles both '###-##-####' and '#########' formats $ perl -le ' my @c = qw/ 123-45-6789 123456789 / ; foreach my $d ( @c ) { my $e = $d; $e =~ s/^(\d+)(-?)(\d+)(-?)(\d{4})$/ q{#} x length($1) . $2 . q{#} x length($3) . $4 . $5/egimsx; print $e; }' ###-##-6789 #####6789

    Hope that helps.

      Thank You works Perfectly!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11104203]
Approved by Marshall
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-20 02:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found