Bootstrap

简单介绍一下c++正则表达式

目录

1.正则表达式的需求

1.1普通字符

1.2特殊字符

1.3限定字符

2 std::regex极其相关

2.1regex_match

2.2regex_replace and regex_search

3 常用的regex

3.1检验数字表达式

 3.2检验字符串表达式

 3.3检验特殊表达式


1.正则表达式的需求

1.检查一个串是否包含某种形式的子串;

2.将匹配的子串替换

3.从某个串中取出符合条件的子串。

1.1普通字符

普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。

1.2特殊字符

特殊字符是正则表达式里有特殊含义的字符,也是正则表达式的核心匹配语法。参见下表:

特殊字符描述

$

匹配输入字符串的末尾位置
*匹配前面的子表达零次或多次
+匹配前面的子表达零次或多次
[标记一个中括号表达式开始
?匹配前面子表达式零次或一次,或指明非贪婪限定符
\

将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如,n匹配字符n。\n 匹配换行符。序列\\匹配\字符,而\则匹配‘(·字符。

~匹配输人字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。
 
{标记限定符表达式开始
\|

指明两项之间的一个选择

补充:

(,)标记一个子表达式的开始和结束位置,子表达式可以供以后使用

    .  :匹配前面除\n之外的任何单字符

1.3限定字符

限定符用来指定正则表达式的一个给定的组件必须要出现多少次才能满足匹配。见下表:

字符描述
*匹配前面的子表达式零次或多次。例如,foo* 能匹配 fo 以及 foooo。* 等价于 {0,}。
+匹配前面的子表达式一次或多次。例如,foo+ 能匹配 foo 以及 foooo,但不能匹配 fo。+ 等价于 {1,}。
匹配前面的子表达式零次或一次。例如,Your(s)? 可以匹配 Your 或 Yours 中的 Your 。? 等价于 {0,1}。
{n}n 是一个非负整数。匹配确定的 n 次。例如,o{2} 不能匹配 for 中的 o,但是能匹配 foo 中的两个 o。
{n,}n 是一个非负整数。至少匹配 n 次。例如,o{2,} 不能匹配 for 中的 o,但能匹配 foooooo 中的所有 o。o{1,} 等价于 o+。o{0,} 则等价于 o*。
{n,m}m 和 n 均为非负整数,其中 n 小于等于 m。最少匹配 n 次且最多匹配 m 次。例如, o{1,3} 将匹配 foooooo 中的前三个 o。o{0,1} 等价于 o?。注意,在逗号和两个数之 间不能有空格。

2 std::regex极其相关

2.1regex_match

对字符串内容进行匹配的最常见手段就是使用正则表达式。可惜在传统 C++ 中正则表达式一直没 有得到语言层面的支持,没有纳入标准库,而 C++ 作为一门高性能语言,在后台服务的开发中,对 URL 资源链接进行判断时,使用正则表达式也是工业界最为成熟的普遍做法。

C++11 提供的正则表达式库操作 std::string 对象,模式 std::regex (本质是 std::basic_regex) 进行初始化,通过 std::regex_match 进行匹配,从而产生 std::smatch(本质是 std::match_results 对象)。

我们通过一个简单的例子来简单介绍这个库的使用。考虑下面的正则表达式:

[a-z]+\.txt: 在这个正则表达式中, [a-z] 表示匹配一个小写字母, + 可以使前面的表达式匹配多 次,因此 [a-z]+ 能够匹配一个小写字母组成的字符串。在正则表达式中一个 . 表示匹配任意字 符,而 \. 则表示匹配字符 .,最后的 txt 表示严格匹配 txt 则三个字母。因此这个正则表达式的 所要匹配的内容就是由纯小写字母组成的文本文件。

std::regex_match 用于匹配字符串和正则表达式,有很多不同的重载形式。最简单的一个形式就是 传入 std::string 以及一个 std::regex 进行匹配,当匹配成功时,会返回 true,否则返回 false。例 如:

#include <iostream>
#include <string>
#include <regex>
int main() {
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
// 在 C++ 中 \ 会被作为字符串内的转义符,为使 \. 作为正则表达式传递进去生效,需要对 \ 进行二次转义,从而有 \\.
std::regex txt_regex("[a-z]+\\.txt");
for (const auto &fname: fnames)
std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
}

结果:
foo.txt: 1
bar.txt: 1
test: 0
a0.txt: 0
AAA.txt: 0

 另一种常用的形式就是依次传入 std::string/std::smatch/std::regex 三个参数,其中 std::smatch 的本质其实是 std::match_results。在标准库中,std::smatch 被定义为了 std::match_results, 也就是一个子串迭代器类型的 match_results。使用 std::smatch 可以方便的对匹配的结果进行获取

#include<iostream>
#include<string>
#include<regex>

int main()
{
    std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
// 在 C++ 中 \ 会被作为字符串内的转义符,为使 \. 作为正则表达式传递进去生效,需要
    std::regex base_regex("([a-z]+)\\.txt");
    std::match_results<std::string::const_iterator> base_match;
    for(const auto& fname : fnames)
    {
        if(std::regex_match(fname,base_match,base_regex))
        {
            // std::smatch 的第一个元素匹配整个字符串
            // std::smatch 的第二个元素匹配了第一个括号表达
            if (base_match.size() == 2){
            std::string base = base_match[1].str();
            std::cout << "sub-match[0]: " << base_match[0].str() << std::endl;
            std::cout << fname << " sub-match[1]: " << base << std::endl;
            } 

        }
    }
}

sub-match[0]: foo.txt foo.txt

sub-match[1]: foo

sub-match[0]: bar.txt bar.txt

sub-match[1]: bar

regex_search:搜索匹配,即搜索字符串中存在符合规则的子字符串。
regex_replace: 替换匹配,即可以将符合匹配规则的子字符串替换为其他字符串。(会改变字符串本身)

测试代码   regex_search:

#include<regex>
#include<string>
#include<iostream>
int main() 
{
	std::string str = "hello2012-12-12world!!!!!";
	std::match_results<std::string::const_iterator> match;
	std::regex pattern("(\\d{4})-(\\d{1,2})-(\\d{1,2})");

	if (std::regex_search(str,match,pattern))
	{	
		for (size_t i = 1; i < match.size(); ++i)
		{
			std::cout << match[i] <<std:: endl;
		}
	}
	return 0;
}
//
2012
12
12

测试代码:regex_replace

#include<regex>
#include<string>
#include<iostream>
using namespace std;


int main() 
{
	
    string str = "2019-08-07";

	cout << regex_replace(str, regex("-"), "/") << endl;
	cout << str << endl;
	return 0;

}

3 常用的regex

3.1检验数字表达式

数字 : ^[0-9]*$
n 位的数字 : ^\d{n}$
至少 n 位的数字 : ^\d{n,}$
m-n 位的数字 : ^\d{m,n}$
零和非零开头的数字 : ^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字 : ^([1-9][0-9]*)+(.[0-9]{1,2})?$
带 1~2 位小数的正数或负数 : ^(\-)?\d+(\.\d{1,2})?$
正数 , 负数 , 和小数 : ^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数 : ^[0-9]+(.[0-9]{2})?$
有 1~3 位小数的正实数 : ^[0-9]+(.[0-9]{1,3})?$
非零的正整数 : ^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数 : ^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$
非负整数 : ^\d+$ 或 ^[1-9]\d*|0$
非正整数 : ^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数 : ^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数 : ^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数 : ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数 : ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数 : ^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$


 

 3.2检验字符串表达式

汉字 : ^[\u4e00-\u9fa5]{0,}$
英文和数字 : ^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为 3~20 的所有字符 : ^.{3,20}$
由 26 个英文字母组成的字符串 : ^[A-Za-z]+$
由 26 个大写英文字母组成的字符串 : ^[A-Z]+$
由 26 个小写英文字母组成的字符串 : ^[a-z]+$
由数字和 26 个英文字母组成的字符串 : ^[A-Za-z0-9]+$
由数字 , 26 个英文字母或者下划线组成的字符串 : ^\w+$ 或 ^\w{3,20}$
中文 , 英文 , 数字包括下划线 : ^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文 , 英文 , 数字但不包括下划线等符号 : ^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\"等字符 : [^%&',;=?$\x22]+
禁止输入含有 ~ 的字符 : [^~\x22]+
 

 3.3检验特殊表达式

Email 地址 : ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名 : [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL : [a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码 : ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
电话号码("XXX-XXXXXXX" , "XXXX-XXXXXXXX" , "XXX-XXXXXXX" , "XXX-XXXXXXXX" , "XXXXXXX"和"XXXXXXXX) : ^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码 (0511-4405222 , 021-87888822) : \d{3}-\d{8}|\d{4}-\d{7}
身份证号 (15 位 , 18 位数字) : ^\d{15}|\d{18}$
短身份证号码 (数字 , 字母 x 结尾) : ^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
帐号是否合法(字母开头,允许 5~16 字节,允许字母数字下划线) : ^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码 (以字母开头,长度在 6~18 之间,只能包含字母 , 数字和下划线) : ^[a-zA-Z]\w{5,17}$
强密码 (必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8~10 之间) : ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式 : ^\d{4}-\d{1,2}-\d{1,2}
一年的 12 个月(01~09和1~12) : ^(0?[1-9]|1[0-2])$
一个月的 31 天(01~09和1~31) : ^((0?[1-9])|((1|2)[0-9])|30|31)$

 

;