基于C语言实现符合PCI合规的信用卡号正则匹配方案问询
在C语言中用PCRE实现符合PCI合规的信用卡号匹配方案
Hey, 刚好我之前做过PCI合规相关的DLP监控项目,完全懂你不想重复造轮子的心态,而且POSIX regex.h确实太老旧,处理空格/短横线这种灵活格式根本不够用。下面给你一套完整的PCRE实现方案,既兼容你现有的正则逻辑,又满足PCI合规的核心要求(包括Luhn校验,这个是很多人容易漏掉的关键点)。
第一步:把你的Python正则转成PCRE兼容版本
假设你之前的Python正则是针对Visa/Mastercard/AMEX的标准格式,我们只需要在数字段之间加入[\s-]*来支持任意数量的空格或短横线分隔。整合后的PCRE正则如下,直接能用:
^(?:4[\s-]*[0-9]{12}(?:[\s-]*[0-9]{3})?|(?:5[1-5][\s-]*[0-9]{14}|2[2-7][\s-]*[0-9]{14})|3[47][\s-]*[0-9]{13})$
- 解释:
[\s-]*匹配任意数量(包括0)的空格或短横线,完美兼容用户输入的各种格式(比如4111111111111111、4111-1111-1111-1111、4111 1111 1111 1111)。
第二步:C语言+PCRE完整代码实现
首先确保你的系统安装了PCRE库(Ubuntu:apt install libpcre3-dev;CentOS:yum install pcre-devel),然后看下面的可运行代码:
示例代码(包含格式匹配+Luhn校验)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pcre.h> // 实现Luhn校验算法——PCI合规必须验证,否则格式对但卡号无效也不符合要求 int luhn_validate(const char *pan) { int total = 0; int alternate = 0; int len = strlen(pan); // 从右往左遍历卡号 for (int i = len - 1; i >= 0; i--) { // 跳过非数字字符(空格、短横线) if (!(pan[i] >= '0' && pan[i] <= '9')) continue; int digit = pan[i] - '0'; if (alternate) { digit *= 2; // 如果乘积大于9,减去9(等价于取各位和) if (digit > 9) digit -= 9; } total += digit; alternate = !alternate; } // 总和能被10整除则有效 return (total % 10 == 0); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <credit_card_number>\n", argv[0]); return EXIT_FAILURE; } const char *card_pattern = "^(?:4[\\s-]*[0-9]{12}(?:[\\s-]*[0-9]{3})?|(?:5[1-5][\\s-]*[0-9]{14}|2[2-7][\\s-]*[0-9]{14})|3[47][\\s-]*[0-9]{13})$"; const char *pcre_error; int error_offset; pcre *regex; // 编译正则表达式 regex = pcre_compile( card_pattern, PCRE_CASELESS, // 这里卡号都是数字,其实无所谓,但加上更通用 &pcre_error, &error_offset, NULL ); if (!regex) { fprintf(stderr, "PCRE编译失败,偏移量 %d: %s\n", error_offset, pcre_error); return EXIT_FAILURE; } // 执行匹配 int match_offsets[30]; // 存储匹配结果的位置,足够覆盖所有情况 int match_result = pcre_exec( regex, NULL, argv[1], strlen(argv[1]), 0, 0, match_offsets, 30 ); // 验证格式和Luhn校验 int is_format_valid = (match_result >= 0); int is_luhn_valid = luhn_validate(argv[1]); if (is_format_valid && is_luhn_valid) { printf("✅ 符合PCI合规的有效信用卡号\n"); } else { if (!is_format_valid) { printf("❌ 卡号格式无效,不匹配Visa/Mastercard/AMEX规则\n"); } if (!is_luhn_valid) { printf("❌ Luhn校验失败,卡号本身无效\n"); } } // 释放PCRE资源 pcre_free(regex); return EXIT_SUCCESS; }
编译命令
gcc -o pan_validator pan_validator.c -lpcre
第三步:适配到你的监控/DLP系统
- 如果你要扫描文件或内存中的PAN,只需要把匹配逻辑封装成一个函数,遍历目标内容,用
pcre_exec逐段检查即可。 - 注意:PCI DSS要求禁止存储完整PAN(除非有严格的访问控制和加密),所以你的系统应该标记出所有完整PAN的存储位置,以便后续整改。
额外优化建议
- 性能优化:如果是批量扫描大文件,建议使用
pcre_dfa_exec代替pcre_exec,它更适合批量匹配,性能更优。 - 扩展卡组织:如果需要支持Discover、JCB等其他卡组织,只需要在正则中添加对应的分支即可。
- 严格分隔符控制:如果只允许单个空格/短横线分隔,可以把
[\s-]*换成[\s-]?,但*更灵活,适配大多数用户输入场景。
内容的提问来源于stack exchange,提问作者LUser
相关产品推荐
相关产品推荐

