使用C或C++高效进行正则表达式匹配

138 阅读2分钟

在Python中,可以使用re.findall(pattern, string)来返回字符串中所有不重叠的模式匹配结果。例如,在下面的SVG路径命令中:

huake_00015_.jpg

import re
spam = "M317.0,169.7C311.1,170.5 285.7,146.8 300.7,178.57 L 321.4,175.01"
eggs = re.findall("([A-Za-z]|-?[0-9]+.?[0-9]*(?:e-?[0-9]*)?)", spam)
print(eggs)
# 输出:['M', '317.0', '169.7', 'C', '311.1', '170.5', '285.7', '146.8', '300.7', '178.5', 'L', '321.4', '175.0']

然而,在C或C++中,有没有一种轻量级、简洁高效的方法来进行这种类型的正则表达式模式匹配呢?需要注意的是,这里不希望使用依赖于Boost的解决方案。理想情况下,希望最小化依赖项并保持代码精简。

2、解决方案

方法一:使用SLRE库

SLRE是一个ANSI C库,实现了一小部分Perl正则表达式。它主要针对那些想要解析配置文件并且速度无关紧要的开发人员。它只有一个.c文件,很容易根据自己的需求进行修改。例如,如果想要引入一个新的元字符'\i',表示'IP地址',就可以轻松地做到。

SLRE的特点:

  • 跨平台 - 纯ANSI C
  • 非常简单的API
  • 轻量级:编译后大约5kB的代码
  • 不使用动态内存分配
  • 线程安全

SLRE支持的正则表达式语法: ^ 匹配缓冲区的开头 $ 匹配缓冲区的末尾 () 分组和子字符串捕获 [...] 匹配集合中的任何字符 [^...] 匹配除集合中的字符之外的任何字符 \s 匹配空白字符 \S 匹配非空白字符 \d 匹配十进制数字 \r 匹配回车 \n 匹配换行

  •           匹配一次或多次(贪婪)
    

+? 匹配一次或多次(非贪婪)

  •           匹配零次或多次(贪婪)
    

? 匹配零次或多次(非贪婪) ? 匹配零次或一次 \xDD 匹配具有十六进制值0xDD的字节 \meta 匹配元字符之一:^$().[+?\

方法二:使用C++正则表达式库

C++没有原生的(或STL)正则表达式支持,因此需要一个C++正则表达式库。有许多这样的库,但它们会创建依赖项。

使用C++正则表达式库的好处:

  • 丰富且强大的正则表达式支持
  • 可以很容易地创建复杂和嵌套的正则表达式
  • 性能优化

使用C++正则表达式库的缺点:

  • 需要创建一个依赖项
  • 库的API可能不同
  • 库的实现可能会有细微的差异

代码示例

在SLRE中,可以如下使用正则表达式进行匹配:

#include <slre.h>
#include <stdio.h>

int main() {
    char *pattern = "([A-Za-z]|-?[0-9]+\.?[0-9]*(?:e-?[0-9]*)?)";
    char *string = "M317.0,169.7C311.1,170.5 285.7,146.8 300.7,178.57 L 321.4,175.01";

    slre_compile(pattern);
    slre_match();

    int n = slre_nsubpatterns();
    for (int i = 0; i < n; i++) {
        printf("%s\n", slre_get_string(i));
    }

    return 0;
}

在C++中,可以使用Boost.Regex库进行正则表达式匹配:

#include <boost/regex.hpp>
#include <iostream>

int main() {
    std::string pattern = "([A-Za-z]|-?[0-9]+\.?[0-9]*(?:e-?[0-9]*)?)";
    std::string string = "M317.0,169.7C311.1,170.5 285.7,146.8 300.7,178.57 L 321.4,175.01";

    boost::regex re(pattern);
    boost::sregex_iterator it(string.begin(), string.end(), re);
    boost::sregex_iterator end;

    while (it != end) {
        std::cout << it->str() << std::endl;
        ++it;
    }

    return 0;
}