信用卡与账号掩码正则问题:奇数位卡号掩码异常修复请求
修复奇数位信用卡号掩码异常问题
需求背景
需对两类数据进行掩码处理,仅保留最后4位并维持原格式:
- 信用卡:数字长度12-19位,支持含连字符/空格的格式
- 账号:数字长度为8或9位
输入输出示例
- 纯数字信用卡:
123456789123→xxxxxxxx9123 - 带连字符信用卡:
1234-5678-9123-4567→xxxx-xxxx-xxxx-4567 - 奇数位带连字符信用卡:
1234-5678-9123-4567-891→xxxx-xxxx-xxxx-xxx7-891 - 混合文本场景:
123123123123131For8640→xxxxxxxxxx3131For8640 - 账号:
12345678→xxxx5678 - HTML嵌套场景:
I m paying 2700 dollars with my credit card(<strong>123456789012345</strong>) to my account(<strong>12345678</strong>)→I m paying 2700 dollars with my credit card(<strong>xxxxxxxxxxx2345</strong>) to my account(<strong>xxxx5678</strong>)
现有代码问题
原MaskCreditCardNo方法在处理奇数位数字长度的信用卡号时出现掩码错误:
- 预期结果:
1234-5678-9123-4567-891→xxxx-xxxx-xxxx-xxx7-891 - 实际结果:
1234-5678-9123-4567-891→xxxx-xxxx-xxxx-xxxx-891
问题根源:原代码直接通过CCnumber.Substring(0, CCnumber.Length - 4)截取需掩码的部分,但带格式的信用卡号总长度减去4的范围,无法精准对应前N个需要掩码的数字位置(奇数位卡号的最后4位可能包含非数字字符),导致错误替换了本应保留的数字。
修复后的代码
private static string MaskIfAccountNumber(this string text) { if (string.IsNullOrEmpty(text)) return text; return Regex.Replace(text, "[0-9][0-9 ]{6,}[0-9]", match => { string digits = string.Concat(match.Value.Where(c => char.IsDigit(c))); return digits.Length is 8 or 9 ? new string('x', digits.Length - 4) + digits.Substring(digits.Length - 4) : match.Value; }); } public static string MaskIfContainCreditCardPanorAcctNum(this string value) { if (string.IsNullOrEmpty(value)) return value; var maskedAccountNumber = value.MaskIfAccountNumber(); return maskedAccountNumber.MaskCreditCardNo(); } public static string MaskCreditCardNo(this string value) { if (string.IsNullOrWhiteSpace(value)) return value; return Regex.Replace(value, "(\\d[\\s|-]?){10,}\\d", match => { string ccNumber = match.Value; string digits = string.Concat(ccNumber.Where(c => char.IsDigit(c))); if (digits.Length < 12 || digits.Length > 19) return match.Value; // 收集所有数字在原字符串中的索引 var digitIndices = ccNumber.Select((c, idx) => new { Char = c, Index = idx }) .Where(x => char.IsDigit(x.Char)) .Select(x => x.Index) .ToList(); // 标记最后4个数字的索引为需保留的位置 var keepIndices = digitIndices.Skip(digitIndices.Count - 4).ToHashSet(); // 遍历替换非保留位的数字为x,保留原格式字符 char[] result = ccNumber.ToCharArray(); for (int i = 0; i < result.Length; i++) { if (char.IsDigit(result[i]) && !keepIndices.Contains(i)) { result[i] = 'x'; } } return new string(result); }); }
修复逻辑说明
- 账号掩码:保留原有逻辑,因账号为纯数字或仅含空格,长度固定,直接替换前
长度-4位为x即可。 - 信用卡掩码优化:
- 先提取卡号内所有数字,校验长度是否符合12-19位要求。
- 定位原字符串中所有数字的索引,筛选出最后4个数字的索引作为保留位。
- 遍历原卡号字符串,仅将非保留位的数字替换为
x,完全保留连字符、空格等格式字符。 - 该逻辑不受数字位数奇偶性影响,精准定位需保留的最后4位数字,彻底解决原代码的截取错误问题。
内容的提问来源于stack exchange,提问作者user3665818
相关产品推荐
相关产品推荐

