C# Regex – How to Mask Credit Card Number Before and After Spaces

c++regex

I am having an issue when there is a space before/after in CreditCardNo.

For example from INV 2420852290 to SAV 0165487. Here 2420852290 is 10-digits and still it is getting masked.

For a CreditCardNo, the range is 12-19 digits. The reason is the space (before and after the digits) which is taken that extra 11th and12 character i think.

The regex in use is

(?<=(?<![\d-*])(?=(?:-?[\d*\s]){12,19}(?![\d-*\s]))[\d-*\s]*)[\d*](?!(?:-?[\d*\s]){0,3}(?![\d-*\s]))

I tried below code with above regex. Expected is that all the scenarios along with the one which is asked in question should work as it is. The last 4 digits should always be masked with x.

They can be tested using the URL – https://dotnetfiddle.net/Gopzoz. Thanks

        public static string MaskNewCCNo(this string value)
        {
           var a = Regex.Replace(value, @"(?<=(?<![\d-*])(?=(?:-?[\d*\s]){12,19}(?![\d-*\s]))[\d-*\s]*)[\d*](?!(?:-?[\d*\s]){0,3}(?![\d-*\s]))", "x");

            return a;
        }

Best Answer

Assuming theses numbers can only be separated by one space or hyphen, following two ideas:

  1. By use of \G to chain matches:

    (?:\G(?!^)|(?<!\d[ -]?)(?=(?:[ -]?\d){12,19}(?![ -]?\d)))\d(?=(?:[ -]?\d){4})([ -]?)
    

    See this demo regexstorm or your updated sample - replace with x$1 (capture of group 1)

    This will first find a number between 12 and 19 characters and chain matches from there. The second lookahead will check at each matching digit if there are at least four digits ahead.

  2. Similar to your current pattern:

    \d(?<=(?=(?:[ -]?\d){12,19}(?![ -]?\d))(?<!\d)(?>[ -]?\d)*)(?=(?:[ -]?\d){4})
    

    Demo at regexstorm or updated .NET demo - replace just with x (like your current code)

    This will do the whole lookaround checks at each digit found and is probably more costly.
    (the atomic group at (?>[ -]?\d)* will prevent matching such as 0 1234567890123456789)

The reason your current regex did not work for the sample lies in (?<![\d-*]) which purpose is meant to separate the whole number from text but it just checks for one of the listed characters. Together with [\d*\s]){12,19} that could match the specified amount of digits or whitespace.

Besides I would not use something like [\d-*\s]. In this case (.NET regex) there is no error but it still looks ugly. An unescaped hyphen inside a character class is used to denote a character range. To match a literal hpyhen put it at start/end of the character-class or escape it with a backslash.

Related Question