This page say :

请选择一篇博客进行编辑

正则表达式regex

参考

regex可以很简单 也可以很复杂

/* 限定符                                           修饰前面的一个字符,可以是元字符
 *                     重复0次或更多次
 +                     重复1次或更多次               []里的+就只是一个"+"字符了           
 ?                     重复0或1次 
 {n}                   重复n次
 {n,}                  重复n或更多次
 {n,m}                 重复n到m次

例:abc* 表示可匹配 以ab 开头后面没有c或有多个c       
  \d{5} 表示\d匹配到的数字连续出现5次

元字符                                                 匹配单个字符
.                      匹配除换行符以外的任意单个字符
^                      表示匹配行首的文本(以什么表达式开始)
$                      表示匹配行尾的文本(以什么表达式结束)
\s                     匹配任意的空白
\S                     匹配任意不是空白符的字符
\d                     匹配数字
\D                     匹配任意非数字的字符
\w                     匹配字母或数字或下划线
\W                     匹配不是字母数字下划线的字符
\b	                   匹配一个单词边界 所谓'单词边界' 请参考https://blog.csdn.net/weixin_42636353/article/details/82466892
\B	                   非字边界匹配。

其他
[]                      匹配其中的任意一个字符  相当于或的意思   [abcd]
[^]                     匹配除了方括号内的字符  相当于取反   [^abcd]
[n-m]                   匹配n到m范围内的任意 一个字符        [0-9] 这是\d的全写       [^0-9] 这是\D的全写 可和其她范围连用  [0-9A-z_]
\                       转义符 转特殊字符为要匹配的字符      \.  匹配.     \\  匹配\  \/ 匹配/
|                       前面一大部分或者后面一大部分    如果要改变范围可用()   如     b(o|a)y    匹配boy bay
[\u4e00-\u9fa5]         匹配汉字

正则表达式还有很多还有待深究

单词边界

  • 单词边界是指一个单词的开头或结尾,或者一个单词和一个非单词字符之间的位置。

在正则表达式中,单词边界是用\b表示,它并非指字符,而是指单词和非单词之间的位置,比如一个单词后面跟着一个空格,那么这个空格和这个单词之间就是一个单词边界。除了单词边界和非单词边界表示位置外,行首^和行尾$也是表示位置。

捕获组

  • (组) 用圆括号分组
// 原始字符串,由 '|' 分隔
std::string s = "part1|part2|part3";

// 正则表达式模式,匹配由 '|' 分隔的第二部分
// 我们使用捕获组来保留前后部分
std::regex pattern("(\\w+)\\|(\\w+)\\|(\\w+)");

// 替换字符串,捕获到的用replacement的内容替换 下面这是种拼接
std::string replacement = "$1|new_part|$3";

// 使用正则表达式进行替换
std::string result = std::regex_replace(s, pattern, replacement);
// 输出替换后的字符串
std::cout << result << std::endl;

输出:

part1|new_part|part3

        // 原始字符串
        std::string s = "The quick brown fox jumps over the lazy dog dog";

        // 正则表达式,匹配重复的单词
        std::regex e("(\\b\\w+)\\s+\\1\\b");

        // 替换字符串,其中\\1是一个反向引用,引用了第一个捕获组
        std::string r = "$1"; // 只保留第一个匹配的单词  或者"555"替换 上面的 重复的dog

        // 执行替换
        std::string result = std::regex_replace(s, e, r);

        // 输出结果
        std::cout << result << std::endl;

输出:

The quick brown fox jumps over the lazy dog

反向引用 与 提取数据

  • 上面$1 (这里1是组号 表示第一个组) 就是提取匹配组匹配到的数据
    std::string s = "I have an apple apple2.";
    std::regex e(R"((apple)\s+(apple2))");
    std::string r = R"($2 orange1)"; // 使用$1引用第一个捕获组,即第一个"apple"
    std::string result = std::regex_replace(s, e, r); //
    std::cout<<result<<std::endl;
    
    >.R"()"是CLion编译器提供支持的被其修的字面字符量不需要手动转义转义字符的写法
    输出:

    I have an apple2 orange1.

  • 反向引用
    假设你想在一个字符串中查找连续重复的单词,如"the the"或"is is"。你可以使用以下正则表达式
    std::regex e("(\\b\\w+)\\s+\\1\\b");
    
    上面的 \1 就是反向引用第一组的内容

先行断言

  • 正向先行断言
    (?=p) 匹配后面紧挨着p的字符, p可以是多个字符 也可以是匹配规则
    std::string s = "123 abc 456, 7890, more text 123";
    std::regex e("(\\d+)(?=,)"); // 匹配数字,后面紧跟着一个逗号(但不包括逗号)
    
    // 使用sregex_iterator进行匹配
    std::sregex_iterator begin(s.begin(), s.end(), e);
    std::sregex_iterator end;
    
    for (std::sregex_iterator i = begin; i != end; ++i) {
        std::smatch match = *i;
        std::string match_str = match.str();
        std::cout << "Matched: " << match_str << std::endl;
    }
    
    输出:

    456
    7890

    std::string s = "123 abc 456, 7890, more text 123";
    std::regex e("(\\d+)(?= [A-z])"); // 匹配后面是空格,然后后面紧跟着一个字母的数字
    
    // 使用sregex_iterator进行匹配
    std::sregex_iterator begin(s.begin(), s.end(), e);
    std::sregex_iterator end;
    
    for (std::sregex_iterator i = begin; i != end; ++i) {
        std::smatch match = *i;
        std::string match_str = match.str();
        std::cout << "Matched: " << match_str << std::endl;
    }
    
    输出:

    123

  • 负向先行断言
    (?!p) 匹配 后面没有紧挨着p的字符
  • 注意事项
    • 先行断言是一种零宽断言,这意味着它不会消耗任何字符,只是简单地检查后续字符是否满足某个条件。
    • 先行断言在性能上可能比较昂贵,因为它需要“向前看”来检查条件是否满足。在复杂的正则表达式或大型文本中,这可能会影响匹配的速度。

非捕获括号

  • (?:p) 分组而不捕获,看起来像分组, 其实不算进分组的引用里面
  • 所以无法$1 \1这样引用到非捕获括号匹配的数据因为它没有捕获
  • 这意味着如果混合在捕获分组里, 也不会影响捕获分组的引用顺序
  • 在一些需要把其作为匹配条件, 但又不需要引用到其匹配的字符的场景下可能有用
std::string s = "123 abc 456,456 7890, more text 123";
std::regex e("(123).*(?:abc).*(456).*(\\2)");//这里第二个分组是456 引用它

std::string r = R"($2 orange1)"; // 使用$2引用第二个捕获组,即 456
std::string result = std::regex_replace(s, e, r); // 
std::cout<<result<<std::endl;

输出:

456 orange1 7890, more text 123

贪婪匹配 & 惰性匹配

  • 默认是贪婪匹配, 尽可能多的匹配
    比如我要匹配以 lib 开始的 以 .dll 结尾的
std::string long_string = "sadfd-_libshdf*-.-.dll sadf libhello.dll libsome-1.0.dll aaa";

// 定义正则表达式模式
std::regex pattern(R"(lib.*\.dll)");

// 使用 sregex_iterator 查找所有匹配项
auto begin = std::sregex_iterator(long_string.begin(), long_string.end(), pattern);
auto end = std::sregex_iterator();

// 遍历所有匹配项并输出
for (std::sregex_iterator i = begin; i != end; ++i) {
    std::smatch match = *i; // 获取当前匹配项
    std::cout << "'" << match.str() << "' 在长字符串中匹配成功\n";
}

输出:

'libshdf*-.-.dll sadf libhello.dll libsome-1.0.dll' 在长字符串中匹配成功

但里面嵌套了一些符合要求的
如果我想要就近结束一段匹配, 就需要使用惰性匹配
在量词后面加个问号就能实现惰性匹配

std::string long_string = "sadfd-_libshdf*-.-.dll sadf libhello.dll libsome-1.0.dll aaa";

// 定义正则表达式模式
std::regex pattern(R"(lib.*?\.dll)");

// 使用 sregex_iterator 查找所有匹配项
auto begin = std::sregex_iterator(long_string.begin(), long_string.end(), pattern);
auto end = std::sregex_iterator();

// 遍历所有匹配项并输出
for (std::sregex_iterator i = begin; i != end; ++i) {
    std::smatch match = *i; // 获取当前匹配项
    std::cout << "'" << match.str() << "' 在长字符串中匹配成功\n";
}

输出:

'libshdf*-.-.dll' 在长字符串中匹配成功
'libhello.dll' 在长字符串中匹配成功
'libsome-1.0.dll' 在长字符串中匹配成功

posted @ 2024-02-09 18:14  Computer_Tech  阅读(6)  评论(0编辑  收藏  举报