C++11 正则表达式匹配

文章目录

  • 前言
  • 一、简介
    • 1.1 简介
    • 1.2 字符规则
    • 1.3 使用1
    • 1.4 使用2
  • 二、代码示例

前言

在Linux平台使用 ss 命令 -p 选项:

-p, --processes
       Show process using socket.

比如:

Process
users:(("node",pid=13051,fd=22))
users:(("sshd",pid=11700,fd=4),("sshd",pid=11659,fd=4))

显示使用该socket的进程的信息如上述格式所示,一个socket可以有多个进程使用。接下来我们根据上述字符串用正则表达式来提取出一个socket多个进程时,其进程的信息。

一、简介

1.1 简介

正则表达式是一种用于描述文本模式的语言,常用于字符串匹配、搜索和替换等操作。

C++11 中引入了一个新的标准库,即 ,该库提供了一套正则表达式类和算法,用于对字符串进行正则表达式匹配、搜索和替换等操作。

std::regex 对象的构造函数接受一个字符串参数,表示正则表达式模式。正则表达式模式是一种特殊的字符串,用于描述文本模式。正则表达式模式中包含了一些特殊字符和语法,用于指定匹配规则和匹配范围。例如,在正则表达式模式中,^ 表示文本的开头,$ 表示文本的结尾,. 表示任意字符,* 表示匹配零个或多个字符,+ 表示匹配一个或多个字符,[] 表示匹配一组字符中的任意一个,() 表示将匹配结果保存到一个子匹配组中等等。

匹配操作通常使用 std::regex_match、std::regex_search、std::regex_replace 等函数来实现。这些函数接受一个字符串参数和一个正则表达式对象,用于对字符串进行匹配、搜索和替换等操作。其中,std::regex_match 函数用于对整个字符串进行匹配,std::regex_search 函数用于在字符串中搜索匹配项,std::regex_replace 函数用于替换字符串中的匹配项。

1.2 字符规则

正则表达式是一个用于描述字符串模式的语言,可以用于匹配、查找、替换字符串中的文本。在正则表达式中,有一些特殊的字符和规则,需要特别注意。

下面是一些常见的正则表达式中的字符和规则:

.:匹配任何一个字符,除了换行符 \n。
*:匹配前面的字符或字符类零个或多个。
+:匹配前面的字符或字符类一个或多个。
?:匹配前面的字符或字符类零个或一个。
[]:匹配括号中的任何一个字符。例如,[abc] 匹配字符 a、b 或 c。
[^]:匹配除了括号中的任何一个字符之外的任何一个字符。例如,[^abc] 匹配除了字符 a、b 和 c 之外的任何一个字符。
|:表示或。例如,a|b 匹配字符 a 或 b。
():用于分组,可以将多个字符或字符类组合在一起。例如,(ab)+ 匹配一个或多个连续的 ab。
^:表示行首,用于匹配字符串的开头。例如,^abc 匹配以 abc 开头的字符串。
$:表示行尾,用于匹配字符串的结尾。例如,abc$ 匹配以 abc 结尾的字符串。
\d:匹配任何一个数字字符,等价于 [0-9]。
\w:匹配任何一个单词字符,包括字母、数字和下划线,等价于 [a-zA-Z0-9_]。
\s:匹配任何一个空白字符,包括空格、制表符和换行符。
\b:匹配单词边界,即单词和非单词字符之间的位置。

需要注意的是,在正则表达式中,一些字符和符号具有特殊的含义,例如 .*+? 等等,如果需要匹配这些字符本身,需要使用转义符号 \ 来将其转义,例如 \\.、\\*、\\+、\\? 等等。

除了前面提到的字符和规则之外,正则表达式还有一些高级的用法,可以用于更复杂的文本处理。下面是一些常见的高级用法:

{n,m}:匹配前面的字符或字符类至少 n 次,最多 m 次。例如,a{2,3} 匹配两个或三个连续的字符 a。
{n,}:匹配前面的字符或字符类至少 n 次。例如,a{3,} 匹配三个或更多连续的字符 a。
{,m}:匹配前面的字符或字符类最多 m 次。例如,a{,3} 匹配零个、一个、两个或三个连续的字符 a。
():用于捕获分组,可以将匹配的结果存储到一个变量中。例如,([a-z]+) 匹配一个或多个小写字母,并将结果存储到一个变量中。
(?:):用于非捕获分组,可以将多个字符或字符类组合在一起,但不会将结果存储到一个变量中。例如,(?:ab)+ 匹配一个或多个连续的 ab,但不会将结果存储到一个变量中。
(?=):用于正向先行断言,表示前面的字符或字符类必须匹配成功,但不会将其包含在匹配结果中。例如,\\d+(?=) 匹配一个或多个数字字符,但只有在其后面紧跟着一个 元 字符时才匹配成功。
(?!):用于负向先行断言,表示前面的字符或字符类必须匹配失败,但不会将其包含在匹配结果中。例如,\\d+(?!) 匹配一个或多个数字字符,但只有在其后面不紧跟着一个 元 字符时才匹配成功。

1.3 使用1

标准库中,最常用的类是 std::regex,它表示一个正则表达式对象。std::regex 对象可以通过构造函数来创建,并接受一个字符串参数,表示要匹配的正则表达式模式。例如:

std::regex pattern("\\d+"); // 匹配一个或多个数字

可以使用 std::regex_match、std::regex_search、std::regex_replace 等函数对字符串进行正则表达式匹配、搜索和替换等操作。

std::regex_match 函数用于对整个字符串进行匹配,如果匹配成功则返回 true,否则返回 false。例如:

std::string s = "123";
std::regex pattern("\\d+");
if (std::regex_match(s, pattern)) {
    std::cout << "Match!" << std::endl;
} else {
    std::cout << "No match." << std::endl;
}

std::regex_search 函数用于在字符串中搜索匹配项,并返回第一个匹配结果。如果找到匹配项,则返回 true,否则返回 false。例如:

std::string s = "123abc";
std::regex pattern("\\d+");
std::smatch match;
if (std::regex_search(s, match, pattern)) {
    std::cout << "Match found: " << match.str() << std::endl;
} else {
    std::cout << "No match found." << std::endl;
}

std::regex_replace 函数用于替换字符串中的匹配项。例如:

std::string s = "123abc";
std::regex pattern("\\d+");
std::string replacement = "456";
std::string result = std::regex_replace(s, pattern, replacement);
std::cout << "Original string: " << s << std::endl;      // "123abc"
std::cout << "Replaced string: " << result << std::endl; // "456abc"
#include 
#include 
#include 

void fun1()
{
    std::string s = "123";
    std::regex pattern("\\d+");
    if (std::regex_match(s, pattern)) {
        std::cout << "Match!" << std::endl;
    } else {
        std::cout << "No match." << std::endl;
    }    
}

void fun2()
{
    std::string s = "123abc789";
    std::regex pattern("\\d+");
    std::smatch match;
    if (std::regex_search(s, match, pattern)) {
        std::cout << "Match fisrt string found: " << match.str() << std::endl;
    } else {
        std::cout << "No match found." << std::endl;
    }
}

void fun3()
{
    std::string s = "123abc789";
    std::regex pattern("\\d+");
    std::string replacement = "456";
    std::string result = std::regex_replace(s, pattern, replacement);
    std::cout << "Original string: " << s << std::endl;      // "123abc"
    std::cout << "Replaced string: " << result << std::endl; // "456abc"    
}

int main() {
    fun1();
    fun2();
    fun3();
}
$ ./a.out 
Match!
Match fisrt string found: 123
Original string: 123abc789
Replaced string: 456abc456

std::regex pattern(“\d+”); 是一个 C++11 中的正则表达式模式,用于匹配字符串中的数字。

在正则表达式语法中,反斜线 \ 是一个转义字符,用于表示后面的字符具有特殊的意义。\d 表示数字字符。+ 是一个量词,表示匹配前面的模式一次或多次。

因此,\d+ 表示匹配一个或多个数字。

1.4 使用2

除了 std::regex 类之外,C++11 的正则表达式库还引入了一些新的类型和函数,用于更方便地进行正则表达式匹配、搜索和替换等操作。

(1)std::smatch 类型

std::smatch 类型表示一个正则表达式匹配结果的集合。当使用 std::regex_search 或 std::regex_match 函数匹配成功时,这些函数会将匹配结果保存在一个 std::smatch 类型的对象中。std::smatch 对象可以通过下标操作符或迭代器来访问匹配结果。

std::string s = "Hello, world!";
std::regex pattern("\\w+");
std::smatch match;
if (std::regex_search(s, match, pattern)) {
    std::cout << "Match found: " << match.str() << std::endl; // "Hello"
}

上面的代码中,std::regex_search 函数用正则表达式模式 \w+ 在字符串中查找第一个单词,并将匹配结果保存在 std::smatch 类型的对象中。然后使用 match.str() 成员函数来访问匹配结果。

访问匹配结果有两种方式,一种是match.str() 成员函数,一种是match[]。如下所示:

#include 
#include 
#include 

int main() {
    std::string s = "[email protected]";
    std::regex pattern("([^@]+)@([^@]+)");
    std::smatch match;
    if (std::regex_search(s, match, pattern)) {
    
        std::cout << "s: " << match[0] << std::endl; 
        std::cout << "用户名: " << match[1] << std::endl; // "example_user"
        std::cout << "域名: " << match[2] << std::endl; // "example.com"

        std::cout << "s: " << match.str() << std::endl; 
        std::cout << "用户名: " << match.str(1) << std::endl; // "example_user"
        std::cout << "域名: " << match.str(2) << std::endl; // "example.com"
    }  
    return 0;
}
s: example_user@example.com
用户名: example_user
域名: example.com
s: example_user@example.com
用户名: example_user
域名: example.com

(2)std::sregex_iterator 类型
std::sregex_iterator 类型表示一个正则表达式匹配结果的迭代器。当使用 std::sregex_iterator 类型的迭代器遍历匹配结果时,每次迭代返回一个 std::smatch 类型的对象,表示一个匹配项。
例如:

std::string s = "Hello, world!";
std::regex pattern("\\w+");
std::sregex_iterator it(s.begin(), s.end(), pattern);
std::sregex_iterator end;
while (it != end) {
    std::smatch match = *it;
    std::cout << "Match found: " << match.str() << std::endl;
    ++it;
}

上面的代码中,std::sregex_iterator 类型的迭代器 it 用于遍历字符串中的所有单词,并将每个匹配结果保存在 std::smatch 类型的对象中。然后使用 match.str() 成员函数来访问匹配结果。

(3)std::regex_replace 函数的格式化替换功能
C++11 引入了一个新的格式化替换语法,可以在 std::regex_replace 函数中使用。这个语法使用 $N 来表示第 N 个子匹配组中的匹配结果,其中 N 是一个从 0 开始的整数。
例如:

std::string s = "John Smith";
std::regex pattern("(\\w+) (\\w+)");
std::string replacement = "$2, $1";
std::string result = std::regex_replace(s, pattern, replacement);
std::cout << "Original string: " << s << std::endl;      // "John Smith"
std::cout << "Replaced string: " << result << std::endl; // "Smith, John"

上面的代码中,std::regex_replace 函数使用正则表达式 (\w+) (\w+) 匹配字符串中的两个单词,并将它们的顺序颠倒,然后使用 $2, $1 格式的语法将它们替换为新的字符串。

#include 
#include 
#include 

void fun1()
{
    std::string s = "Hello, world!";
    std::regex pattern("\\w+");
    std::smatch match;
    if (std::regex_search(s, match, pattern)) {
        std::cout << "Match found: " << match.str() << std::endl; // "Hello"
    }   
}

void fun2()
{
    std::string s = "Hello, world!";
    std::regex pattern("\\w+");
    std::sregex_iterator it(s.begin(), s.end(), pattern);
    std::sregex_iterator end;
    while (it != end) {
        std::smatch match = *it;
        std::cout << "Match found: " << match.str() << std::endl;
        ++it;
    }
}

void fun3()
{
    std::string s = "John Smith";
    std::regex pattern("(\\w+) (\\w+)");
    std::string replacement = "$2, $1";
    std::string result = std::regex_replace(s, pattern, replacement);
    std::cout << "Original string: " << s << std::endl;      // "John Smith"
    std::cout << "Replaced string: " << result << std::endl; // "Smith, John"  
}


int main() {
    fun1();
    fun2();
    fun3();
}
$ ./a.out
Match found: Hello
Match found: Hello
Match found: world
Original string: John Smith
Replaced string: Smith, John

这个正则表达式 \\w+ 匹配一个或多个连续的单词字符。其中:
\\w 表示匹配任何一个单词字符,包括字母、数字和下划线。这个字符类等价于 [ a-z A-Z 0-9 _ ]。
+表示匹配一个或多个前面的字符或字符类。

二、代码示例

#include 
#include 
#include 
#include 

struct ProcessInfo {
    std::string program_name;
    int pid;
    int fd;

    ProcessInfo(std::string name, int p, int f):
        program_name(name), pid(p), fd(f) {}
};

int main() {
   
    std::string process_info = R"((("task1",pid=11700,fd=4),("task2",pid=11659,fd=4),("task3",pid=12000,fd=4)))";

    //使用了一个正则表达式模式(pattern)来匹配进程信息字符串中的每个进程
    //R"(...)" 表示一个原始字符串字面量,其中 ... 是一个字符串,可以包含任何字符,包括换行符和引号等特殊字符。
    //每个进程信息都是以 ("program_name",pid=pid_value,fd=fd_value) 的形式出现,
    //并且多个进程信息之间用逗号 , 分割
    std::regex pattern(R"(\((\"[^\"]+\"),pid=(\d+),fd=(\d+)\))");

    //使用 std::sregex_iterator 类型的迭代器(it)遍历所有匹配项
    std::sregex_iterator it(process_info.begin(), process_info.end(), pattern);
    std::sregex_iterator end;

    std::vector<ProcessInfo> processes;

    while (it != end) {
        std::smatch match = *it;
        std::string program_name = match[1];
        int pid = std::stoi(match[2]);
        int fd = std::stoi(match[3]);
        processes.emplace_back(ProcessInfo(program_name, pid, fd));
        ++it;
    }

    for (auto& proc : processes) {
        std::cout << "Program name: " << proc.program_name
                  << ", PID: " << proc.pid
                  << ", FD: " << proc.fd
                  << std::endl;
    }

    return 0;
}
# ./a.out
Program name: "task1", PID: 11700, FD: 4
Program name: "task2", PID: 11659, FD: 4
Program name: "task3", PID: 12000, FD: 4

在上面的示例代码中,使用了 std::regex 对象来构建正则表达式模式,然后通过 std::sregex_iterator 类型的迭代器遍历所有匹配项,并使用 std::smatch 类型的对象来保存匹配结果。这些类型都是 C++11 中新引入的,用于对正则表达式进行更方便的匹配、搜索和替换等操作。

其中std::regex pattern:

 std::regex pattern(R"(\((\"[^\"]+\"),pid=(\d+),fd=(\d+)\))");

std::regex 是 C++11 中的正则表达式库,用于构建正则表达式对象。pattern 是一个 std::regex 对象,通过调用 std::regex 构造函数来初始化。

正则表达式模式字符串包含以下几个部分:
(1)R"()" 是原始字符串字面量,表示其中的字符不需要进行转义处理。
(2)( 和 ) 分别表示匹配左括号 ( 和右括号 )。
(3)“[^”]+" 表示匹配双引号 " 中的任意字符,不包括双引号本身。

(\"[^\"]+\"),pid=(\d+),fd=(\d+)

" 表示匹配双引号 “,其中 \ 是转义字符,表示后面的字符是特殊字符。
[^”]+ 表示匹配一个或多个非双引号字符。
(4),pid= 表示匹配逗号 , 后面的字符串 pid=。
(5)(\d+) 表示匹配一个或多个数字。
(6),fd= 表示匹配逗号 , 后面的字符串 fd=。
(7)(\d+) 表示匹配一个或多个数字。

备注: “[^”]+" 表示匹配双引号 " 中的任意字符,不包括双引号本身。这样可以避免匹配到多个进程信息的情况。

因此,这个正则表达式模式可以匹配形如 (“program_name”,pid=pid_value,fd=fd_value) 的字符串,其中 program_name 是由双引号包围的任意字符,pid_value 和 fd_value 是任意数字。

你可能感兴趣的:(modern,C++,c++,正则表达式)