tags:

views:

398

answers:

4

We need to mask credit card numbers.Masking all but last 4 digits. I am trying to use SED. As credit card number length varies from 12 digits to 19,I am trying to write regular expression.Following code will receive the String. If it contains String of the form "CARD_NUMBER=3737291039299199", it will mask first 12 digits. Problem is how to write regular expression for credit card-12 to 19 digits long? If I write another expression for 12 digits, it doesn't work.that means for 12 digit credit card- first 8 digits should be masked. for 15 digit credit card, first 11 digits should be masked.

 while read data; do
    var1=${#data}

    echo "Length is "$var1
    echo $data | sed -e "s/CARD_NUMBER=\[[[:digit:]]\{12}/CARD_NUMBER=\[\*\*\*\*\*\*\*\*/g"
    done
+2  A: 

I'm not much of a sed guru, and thus I cannot manage to do it in only one command, though there surely are ways. But with two sed commands, here is what I got:

sed -e 's/CARD_NUMBER=\([0-9]*\)\([0-9]\{4\}\)/\1\
\2/' | sed -e '1s/./x/g ; N ; s/\n//'

Please note the embedded newline.

Because sed works by lines, I first break the card number into the initial part and the last four digits, separating them by a newline (the first sed command). Then, I mask the initial part (1s/./x/g), and remove the new line (N ; s/\n//).

Good luck!

FX
+1  A: 

How about

sed -e :a -e "s/[0-9]\([0-9]\{4\}\)/\*\1/;ta"

(This works in my shell, but you may have to add or remove a backslash or two.) The idea is to replace a digit followed by four digits with a star followed by the four digits, and repeat this until it no longer triggers.

Beta
Thanks but this given an error-$ echo "4664738575834567" | sed -e :a -e "s/[0-9]\([0-9]\{4\}\)/\*\1/:ta""Unknown option to 's'
Sorry, typo! Try it now.
Beta
Hi ,thanks it works but slight problem.Input is something like-"CARD_NUMEBR=[72727272727272727]" and output should be "CARD_NUMEBR=[************3737]" In above expression, I am trying to put CARD_NUMEBR[but does not work.
Really? It works for me, sed v4.1.5. We can try an experiment. What does this do: echo CARD_NUMBER=[12345689] | sed -e "s/[0-9]([0-9]{4})/*\1/"
Beta
A: 

try this, you don't have to create complicated regex

var1="CARD_NUMBER=3737291039299199"
IFS="="
set -- $var1
cardnumber=$2
echo $cardnumber | awk 'BEGIN{OFS=FS=""}{for(i=1;i<=NF-4 ;i++){ $i="*"} }1'

output

$ ./shell.sh
************9199
ghostdog74
+1  A: 

This does it in one sed command without an embedded newline:

sed -r 'h;s/.*([0-9]{4})/\1/;x;s/CARD_NUMBER=([0-9]*)([0-9]{4})/\1/;s/./*/g;G;s/\n//'

If your sed doesn't have -r:

sed 'h;s/.*\([0-9]\{4\}\)/\1/;x;s/CARD_NUMBER=\([0-9]*\)\([0-9]\{4\}\)/\1/;s/./*/g;G;s/\n//'

If your sed needs -e:

sed -e 'h' -e 's/.*\([0-9]\{4\}\)/\1/' -e 'x' -e 's/CARD_NUMBER=\([0-9]*\)\([0-9]\{4\}\)/\1/' -e 's/./*/g' -e 'G' -e 's/\n//'

Here's what it's doing:

  • duplicate the number so it's in pattern space and hold space
  • grab the last four digits
  • swap them into hold space and the whole number into pattern space
  • grap all but the last four digits
  • replace each digit with a mask character
  • append the last four digits from hold space to the end of the masked digits in pattern space (a newline comes along for free)
  • get rid of the newline
Dennis Williamson
+1 Impressive. But I think the 4th step can be a little shorter: s/[0-9]{4}$//
Beta