You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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的存储位置,以便后续整改。

额外优化建议

  1. 性能优化:如果是批量扫描大文件,建议使用pcre_dfa_exec代替pcre_exec,它更适合批量匹配,性能更优。
  2. 扩展卡组织:如果需要支持Discover、JCB等其他卡组织,只需要在正则中添加对应的分支即可。
  3. 严格分隔符控制:如果只允许单个空格/短横线分隔,可以把[\s-]*换成[\s-]?,但*更灵活,适配大多数用户输入场景。

内容的提问来源于stack exchange,提问作者LUser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:27