2023-03-27 C语言正则表达式库 pcre2 简述(chitGPT给出的回答和我的补充)

井嘉胜
2023-12-01

@[TOC](C语言正则表达式库 pcre2 简述(chitGPT给出的回答和我的补充))


前言

PCRE2(Perl Compatible Regular Expression 2)是一个支持 Perl 语法的正则表达式库。它是 PCRE(Perl Compatible Regular Expression)的升级版,提供了更多的功能和更高的性能。

PCRE2 可以用于 C、C++、Java、Python、PHP 等多种编程语言中,用于处理文本匹配、搜索和替换等操作。


一、pcre2的使用 ( 以下AI给的代码有误, 不要抄, 看最后 )

使用 PCRE2,需要先安装库文件和头文件。然后在代码中包含头文件,调用相应的函数进行正则表达式的操作。例如,以下是一个 C++ 中使用 PCRE2 进行正则表达式匹配的示例:

#include <iostream>
#include <pcre2.h>

int main()
{
    // 定义正则表达式
    PCRE2_SPTR pattern = (PCRE2_SPTR) "hello (world)";

    // 定义输入字符串
    PCRE2_SPTR input = (PCRE2_SPTR) "hello world, hello PCRE2!";

    // 编译正则表达式
    pcre2_code *re;
    int errorcode;
    PCRE2_SIZE erroroffset;
    re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errorcode,
                       &erroroffset, NULL);

    // 匹配正则表达式
    pcre2_match_data *match_data;
    match_data = pcre2_match_data_create_from_pattern(re, NULL);
    int rc;
    rc = pcre2_match(re, input, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL);

    // 输出匹配结果
    if (rc > 0)
    {
        PCRE2_SPTR substring_start;
        PCRE2_SIZE substring_length;
        substring_start =
            pcre2_get_substring(input, match_data, 1, &substring_length);
        std::cout << "Match: ";
        std::cout.write((char *)substring_start, substring_length);
        std::cout << std::endl;
        pcre2_substring_free(substring_start);
    }

    // 释放内存
    pcre2_match_data_free(match_data);
    pcre2_code_free(re);

    return 0;
}

以上代码定义了一个正则表达式 hello (world),表示匹配字符串中的 hello world。然后编译正则表达式,使用 pcre2_match 函数进行匹配,如果成功则输出匹配结果。

PCRE2 还提供了许多其他的函数和选项,可以根据需要进行使用。

二、使用pcre2匹配中文 ( 以下AI给的代码有误, 不要抄, 看最后 )

要在 PCRE2 中匹配中文,您需要考虑以下几点:

中文的编码方式:中文通常使用 UTF-8 编码,所以您需要确保在 PCRE2 中使用 UTF-8 编码。

使用 Unicode 属性:PCRE2 提供了 Unicode 属性,可以识别不同的字符类别,包括中文字符。

以下是一个使用 PCRE2 匹配中文的示例代码:

#include <pcre2.h>
#include <stdio.h>

int main()
{
    const char *pattern = "\\p{Han}+"; // 匹配中文字符
    const char *subject = "你好,世界!Hello, world!";
    PCRE2_SPTR pattern_utf8 = (PCRE2_SPTR)pattern;
    PCRE2_SPTR subject_utf8 = (PCRE2_SPTR)subject;
    int errorcode, rc;
    PCRE2_SIZE erroroffset;
    pcre2_code *re;
    pcre2_match_data *match_data;

    // 编译正则表达式
    re = pcre2_compile(pattern_utf8, PCRE2_ZERO_TERMINATED, 0, &errorcode,
                       &erroroffset, NULL);
    if (re == NULL)
    {
        printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset,
               pcre2_get_error_message(errorcode));
        return 1;
    }

    // 准备匹配数据
    match_data = pcre2_match_data_create_from_pattern(re, NULL);

    // 执行匹配
    rc = pcre2_match(re, subject_utf8, PCRE2_ZERO_TERMINATED, 0, 0, match_data,
                     NULL);
    if (rc < 0)
    {
        printf("PCRE2 matching failed: %d\n", rc);
        return 1;
    }

    // 输出匹配结果
    printf("Matched %d characters:\n", rc);
    PCRE2_SPTR match_str = subject_utf8 + pcre2_get_startchar(match_data);
    for (int i = 0; i < rc; i++)
    {
        printf("%c", (char)match_str[i]);
    }
    printf("\n");

    // 释放资源
    pcre2_match_data_free(match_data);
    pcre2_code_free(re);
    return 0;
}

该示例使用 \p{Han}+ 正则表达式匹配中文字符,输出结果为:

Matched 6 characters:
你好世界

注意,由于中英文字符混合,输出结果可能不是您期望的。如果您只想匹配中文字符,可以将正则表达式修改为 \p{Han}+。


总结

上面是CSDN的AI模型chitGPT做的有关pcre2正常表达式库的简要介绍, 我先验证一下, 看看代码有没有什么问题.

很遗憾, 上面两个代码都有相当错误, 需要修改, 修改后的代码见下面

编译参数:需要引入8位和16位的库(不冲突)

 E:\msys64\clang64\bin\clang.exe -glldb -lpcre2-16 -lpcre2-8 test196_8*.c -o E:\clangC++\answer\C\test196_8.exe

第一个程序:

#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#include <stdio.h>

int main()
{
    // 定义正则表达式
    PCRE2_SPTR pattern = (PCRE2_SPTR) "hell(\\w)"; // (world)";

    // 定义输入字符串
    PCRE2_SPTR input = (PCRE2_SPTR) "hellp hello world,  PCRE2!";

    // 编译正则表达式
    pcre2_code *re;
    int errorcode;
    PCRE2_SIZE erroroffset;
    re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errorcode,
                       &erroroffset, NULL);

    // 匹配正则表达式
    pcre2_match_data *match_data =
        pcre2_match_data_create_from_pattern(re, NULL);

    int rc =
        pcre2_match(re, input, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL);

    PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
    // 输出匹配结果
    while (rc > 0)
    {
        printf("Match: \n");
        PCRE2_SPTR substring_start;
        PCRE2_SIZE substring_length;
        for (int i = 0; i < rc; i++)
        {
            substring_start = input + ovector[2 * i];
            substring_length = ovector[2 * i + 1] - ovector[2 * i];
            printf("%2d: %.*s\n", i, (int)substring_length,
                   (char *)substring_start);
        }

        input = substring_start + substring_length;
        rc = pcre2_match(re, input, PCRE2_ZERO_TERMINATED, 0, 0, match_data,
                         NULL);

        ovector = pcre2_get_ovector_pointer(match_data);
    }

    // 释放内存
    pcre2_match_data_free(match_data);
    pcre2_code_free(re);

    return 0;
}

第二个程序:

#define PCRE2_CODE_UNIT_WIDTH 16
#include <locale.h>
#include <pcre2.h>
#include <stdio.h>

int main()
{
    setlocale(LC_CTYPE, "");

    PCRE2_SPTR16 pattern_utf16 =
        (PCRE2_SPTR16)L"(\\p{Han})+"; // 匹配中文字符pattern;

    PCRE2_SPTR16 subject_utf16 =
        (PCRE2_SPTR16)L"Hello, world! 你好,世界!"; // subject;

    int errorcode;
    int rc;
    size_t erroroffset;
    pcre2_code_16 *re;
    pcre2_match_data_16 *match_data;

    // 编译正则表达式
    re = pcre2_compile_16(pattern_utf16, PCRE2_ZERO_TERMINATED, 0, &errorcode,
                          &erroroffset, NULL);

    if (re == NULL)
    {
        PCRE2_UCHAR16 buffer[256];
        pcre2_get_error_message_16(errorcode, buffer, sizeof(buffer));
        wprintf(L"PCRE2 compilation failed at offset %d: %s\n",
                (int)erroroffset, buffer);
        return 1;
    }

    // 准备匹配数据
    match_data = pcre2_match_data_create_from_pattern_16(re, NULL);

    // 执行匹配
    rc = pcre2_match_16(re, subject_utf16, PCRE2_ZERO_TERMINATED, 0, 0,
                        match_data, NULL);
    if (rc < 0)
    {
        printf("PCRE2 matching failed: %d\n", rc);
        return 1;
    }

    // 输出匹配结果
    printf("Matched %d characters:\n", rc);
    PCRE2_SPTR16 match_str = subject_utf16 + pcre2_get_startchar_16(match_data);
    for (int i = 0; i < rc; i++)
    {
        wprintf(L"%c", (wchar_t)match_str[i]);
    }
    printf("\n");

    // 释放资源
    pcre2_match_data_free_16(match_data);
    pcre2_code_free_16(re);

    return 0;
}

貌似AI对于这个正则库的api并不熟悉, 而且还会自造函数, 这确实令人苦恼, 关键是我想通过AI快速掌握这个库, 结果还是需要看文档.

以下是文档中核心函数的最简要解说.

此正则库有三种编码, 8,16,32位, 对于普通ASCII码, 8位即可, 中文需要16位(Windows环境)

#define PCRE2_CODE_UNIT_WIDTH 16

为了用中文, 需要给出区域头文件, 加上库文件

#include <locale.h>
#include <pcre2.h>

设置中文环境

    const char *loc = setlocale(LC_CTYPE, "");

用宽字符声明模式字符串

    PCRE2_SPTR16 pattern = (PCRE2_SPTR16)L"\\p{Han}+"; // 匹配中文字符pattern;

声明匹配字符串

    PCRE2_SPTR16 subject =
        (PCRE2_SPTR16)L"Hello, world! 你好,世界!"; // subject;

编译正则表达式

    int errorcode;
    size_t erroroffset;

    // 编译正则表达式
    pcre2_code_16 *re = pcre2_compile_16(
        pattern,               // 模式字符串
        PCRE2_ZERO_TERMINATED, // 字符长度
        0,                     // 默认选项
        &errornumber,          // 错误号
        &erroroffset,          // 错误偏移
        NULL);                 // 一般用NULL

如果编译返回NULL, 输出错误结束程序

    if (re == NULL)
    {
        PCRE2_UCHAR16 buffer[256];
        pcre2_get_error_message_16(errorcode, buffer, sizeof(buffer));
        wprintf(L"PCRE2 compilation failed at offset %d: %s\n",
                (int)erroroffset, buffer);
        return 1;
    }

声明一个匹配数据, 用于存放匹配结果

    // 准备匹配数据
    pcre2_match_data_16 *match_data =
        pcre2_match_data_create_from_pattern_16(re, NULL);

执行匹配

    size_t offset = 0;
    // 匹配成功的数量
    int rc = pcre2_match_16(re, 		// 正则表达式
    						subject, 	// 待匹配字符串
    						PCRE2_ZERO_TERMINATED, // 字符串长度
    						offset, 	// 开始匹配时的偏移量
    						0,			// 默认选项
                            match_data, // 匹配数据存放地址
                            NULL		// 默认为NULL
                            );
    if (rc < 0)
    {
        printf("PCRE2 matching failed: %d\n", rc);
        return 1;
    }

获取匹配数组, 匹配位置偏移量存储在此数组中

    size_t *ovector = pcre2_get_ovector_pointer_16(match_data);

输出匹配结果

    while (rc > 0)
    {
        printf("Match: \n");

        for (int i = 0; i < rc; i++)
        {
            wprintf(L"%2d: %.*s\n", i,
                    (int)(ovector[2 * i + 1] - ovector[2 * i]),	// 匹配的开始和结束位置在ovector数组中, 求差得出匹配字符个数 
                    (wchar_t *)(subject + ovector[2 * i]));		// 通过偏移到达匹配位置, 从匹配的第一个字符开始打印
        }

        offset = ovector[2 * (rc - 1) + 1];						// 设置本次匹配字符结尾的偏移量, 做下一次匹配的开始位置
        rc = pcre2_match_16(re, subject, PCRE2_ZERO_TERMINATED, 
        					offset,								// 从上次匹配的末尾开始匹配 
        					0,
                            match_data, NULL);

        ovector = pcre2_get_ovector_pointer_16(match_data);		// 获取匹配结果数组
    }

将正则表达式和匹配数据资源回收

    // 释放资源
    pcre2_match_data_free_16(match_data);
    pcre2_code_free_16(re);

以上就是正则库的简述, 目前还是自己看文档, AI还暂时不能解决这种问题.

 类似资料: