Advertisement

c++primer第十七章 03正则表达式

阅读量:

正则表达式:一种配合string 描述字符序列的的方法,

17.3.1使用正则表达式库

复制代码
       //查找不在字符c之后的字符串ei ,例如:aei,bei, 而不是 cei,cee,cbi
    	string pattern("[^c]ei");
    	//这是用来给regex提供的正则表达式语言用的
    	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]*]";
    	//cout << pattern << endl;
    
    	//构造一个用于查找模式的regex
    	regex r(pattern); 
    	//定义一个对象保存搜素结果
    	smatch results;
    
    	//定义一个string保存与模式匹配和不匹配的文本
    	string test_str = "receipt freind theif receive";
    
    	//用r在test_str中查找与pattern匹配的子串
    	//函数regex_search在输入序列中只要找到一个匹配子串就会停止查找
    	if (regex_search(test_str, results, r))
    	{
    		cout << results.str() << endl;
    	}

指定regex对象的选项

复制代码
    	//一个或多个字母或数字字符后接一个'.',再接“cpp”或“cxx”或“cc”
    	//.通常匹配任意字符,加\去掉特殊含义,但是\又是特殊字符,得再加\ 
    	regex r("[[:alnum:]]+\ .(cpp|cxx|cc)$", regex::icase);
    	smatch results;
    
    	string filename;
    	while (cin >> filename)
    	{
    		if (regex_search(filename, results, r))
    		{
    			cout << results.str() << endl;
    		}
    	}

在明确设置或正确使用正则表达式时会出现问题

复制代码
    	//一个或多个字母或数字字符后接一个'.',再接“cpp”或“cxx”或“cc”
    	//.通常匹配任意字符,加\去掉特殊含义,但是\又是特殊字符,得再加\ 
    	
    	smatch results;
    
    	try {
    		//错误:alnum漏掉了右括号,构造函数抛出异常
    		regex r("[[:alnum:]+\ .(cpp|cxx|cc)$", regex::icase);
    		string filename;
    		while (cin >> filename)
    		{
    			if (regex_search(filename, results, r))
    			{
    				cout << results.str() << endl;
    			}
    		}
    	}
    	catch (regex_error e)
    	{
    		cout << e.what() << "\ncode: " << e.code() << endl;
      }

正则表达式类和输入序列类型

复制代码
    	regex r("[[:alnum:]]+\ .(cpp|cxx|cc)$", regex::icase);
    	//smatch results;
    	//将匹配字符数组输入序列
    	const char* cc = "myfile.cc";
    	cmatch results;
    	//报错的原因是results需要的是一个string输入序列而不是char *
    	if (regex_search(cc, results, r))
    	{
    		cout << results.str() << endl;
    	}

练习17.14
编写几个正则表达式,分别触发不同错误
拿这个代码做实验就行了

复制代码
    	//一个或多个字母或数字字符后接一个'.',再接“cpp”或“cxx”或“cc”
    	//.通常匹配任意字符,加\去掉特殊含义,但是\又是特殊字符,得再加\ 
    
    	smatch results;
    
    	try {
    		//错误:alnum漏掉了右括号,构造函数抛出异常
    		regex r("[[:alnum:]]+\ .(cpp|cxx|cc)$", regex::icase);
    		string filename;
    		while (cin >> filename)
    		{
    			if (regex_search(filename, results, r))
    			{
    				cout << results.str() << endl;
    			}
    		}
    	}
    	catch (regex_error e)
    	{
    		cout << e.what() << "\ncode: " << e.code() << endl;
    	}

通过正则表达式模式识别出违反[i位于e之前的位置(除非i位于c之后)]的单词,并对程序输入的每个单词进行判断以确定其是否符合该规则。

复制代码
    	string x = "[^c]ei";
    	x = "[[:alpha:]]*" + x + "[[:alpha:]]*";
    	regex r(x);
    
    	string s;
    	smatch result;
    	while (cin >> s)
    	{
    		if (regex_search(s, result, r))
    		{
    			cout << "无效" << endl;
    			cout << result.str() << endl;
    		}
    		else
    		{
    			cout << "有效" << endl;
    		}
    	}

练习17-16中使用regex对象并以[^c]ei进行初始化时的结果如何?当采用['^c']'ei'进行初始化时,则会使得仅与以'?'ei'形式开头的字符串产生匹配效果即在输入包含一个特定字符后才开始匹配的情形下 这种情况下的匹配条件为只有当目标字符串以'?' + ei的形式开头时才会被识别并捕获 此外 可参考以下示例来理解其工作原理:例如 当目标字符串为xxeid时 则只有其中符合条件的部分会被提取出来 即最终输出将为xei

17.3.2匹配与Regex迭代器类型

使用sregex_iterator迭代器遍历字符序列

复制代码
    	//查找前一个字符不是c的字符串ei
    	string pattern("[^c]ei");
    	//我们想要包含pattern的单词的全部内容
    	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
    	//icase忽略大小写
    	regex r(pattern, regex::icase);
    
    	string file = "";
    	for (sregex_iterator it(file.begin(), file.end(), r), it_endl; it != it_endl; ++it)
    	{
    		cout << it->str()<<endl;
    	}

使用匹配数据(扩展)

复制代码
    	//查找前一个字符不是c的字符串ei
    	string pattern("[^c]ei");
    	//我们想要包含pattern的单词的全部内容
    	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
    	//icase忽略大小写
    	regex r(pattern, regex::icase);
    
    	string file = "het read or write according to the type being handled. The input operators iqnore whi";
    	for (sregex_iterator it(file.begin(), file.end(), r), it_endl; it != it_endl; ++it)
    	{ 
    		//前缀的大小
    		auto pos = it->prefix().length();
    		//想要的最多40个字符
    		pos = pos > 40 ? pos - 40 : 0;
    
    		//使用prefix表示前缀的一部分
    		cout << it->prefix().str().substr(pos)
    		//匹配regex的单词
    			<< "\n\t\t>>>" << it->str() << "<<<\n"
    		//suffix表示后缀的第一部分
    			<< it->suffix().str().substr(0, 40)
    			<< endl;
    	}

17.3.2节练习
练习17.17更新你的程序,查找输入序列中违反[ei]语法规则的单词

复制代码
    	//查找前一个字符不是c的字符串ei
    	string pattern("[^c]ei");
    	//我们想要包含pattern的单词的全部内容
    	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
    	//icase忽略大小写
    	regex r(pattern, regex::icase);
    
    	string file = "";
    	for (sregex_iterator it(file.begin(), file.end(), r), it_endl; it != it_endl; ++it)
    	{
    		cout << it->str()<<endl;
    	}

练习17.18 忽略包含[ei]但并非拼写错误的单词

复制代码
    	//查找前一个字符不是c的字符串ei
    	string pattern("[^c]ei");
    	//我们想要包含pattern的单词的全部内容
    	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
    	//icase忽略大小写
    	regex r(pattern, regex::icase);
    
    	string file = "cei albeit neighbor het read or write according to the type being handled. The input operators iqnore whi";
    	for (sregex_iterator it(file.begin(), file.end(), r), it_endl; it != it_endl; ++it)
    	{
    
    
    		if (it->str() != "albeit" && it->str() != "neighbor")
    		{
    		cout << it->str() << endl;
        }
    
    	}

17.3.3使用子表达式

使用子匹配操作

复制代码
    void test07()
    {
    //有两个子表达式,1,点之前是文件名的部分,2,点后面表示文件扩展名
    	regex x("([[:alnum:]]+)\ .(cpp|cxx|css)$", regex::icase);
    	smatch results;
    	string filename;
    	while (cin >> filename)
    	{
    		if (regex_search(filename, results, x))
    		{
    		//(1)只打印文件名的部分,后面的扩展名不显示
    			cout << results.str(1) << endl;
    		}
    	}
    
    
    }

子表达式用于数据验证

复制代码
    bool valid(const smatch& m)
    { 
    	//如果区号前面有一个左括号
    	if (m[1].matched)
    	{
    		//则区号后面必须有一个右括号
    		return m[3].matched && (m[4].matched == 0 || m[4].str() == " ");
    	}
    	else
    	{
    		//否则区号后不能有右括号
    		//另外两个组成部分间的分隔符必须匹配
    		return !m[3].matched && m[4].str() == m[6].str();
    	}
    }
    void test08()
    {
    	//ECMAScript正则表达式语言的一些特性
    	//1. (\ ()? 表示区号部分可选的左括号
    	//2. (\ d{3})表示区号
    	//3. (\ ))? 表示区号部分可选的右括号
    	//4. ([-. )? 表示区号部分可选的分隔符
    	//5. (\ d{3}) 表示号码的下三位数字
    	//6. ([-. ])? 表示可选的分割符
    	//7. (\ d{4}) 表示号码的最后四位数字
    
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ])?(\ d{3})([-. ])?(\ d{4})";
    
    	regex r(phone);
    
    	smatch m;
    	string s;
    	while (getline(cin, s))
    	{
    		//对于每个匹配的电话号码
    		for (sregex_iterator it(s.begin(), s.end(), r), end_it; it != end_it; ++it)
    		{
    			//检测格式是否合法
    			if (valid(*it))
    			{
    				cout << "valid: " << it->str() << endl;
    			}
    			else
    			{
    				cout << "now valid" << it->str() << endl;
    			}
    		}
    	}
    }

4

4

4

17.20 编写验证电话号码的程序

复制代码
    bool valid(const smatch& m)
    { 
    	//如果区号前面有一个左括号
    	if (m[1].matched)
    	{
    		//则区号后面必须有一个右括号
    		return m[3].matched && (m[4].matched == 0 || m[4].str() == " ");
    	}
    	else
    	{
    		//否则区号后不能有右括号
    		//另外两个组成部分间的分隔符必须匹配
    		return !m[3].matched && m[4].str() == m[6].str();
    	}
    }
    void test08()
    {
    	//ECMAScript正则表达式语言的一些特性
    	//1. (\ ()? 表示区号部分可选的左括号
    	//2. (\ d{3})表示区号
    	//3. (\ ))? 表示区号部分可选的右括号
    	//4. ([-. )? 表示区号部分可选的分隔符
    	//5. (\ d{3}) 表示号码的下三位数字
    	//6. ([-. ])? 表示可选的分割符
    	//7. (\ d{4}) 表示号码的最后四位数字
    
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ])?(\ d{3})([-. ])?(\ d{4})";
    
    	regex r(phone);
    
    	smatch m;
    	string s;
    	while (getline(cin, s))
    	{
    		//对于每个匹配的电话号码
    		for (sregex_iterator it(s.begin(), s.end(), r), end_it; it != end_it; ++it)
    		{
    			//检测格式是否合法
    			if (valid(*it))
    			{
    				cout << "valid: " << it->str() << endl;
    			}
    			else
    			{
    				cout << "now valid" << it->str() << endl;
    			}
    		}
    	}
    }

17.21 valid函数重写第289页的 电话号码程序

复制代码
    string format(const string& s) { return s; }
    
    struct PersonInfo
    {
    	string name;
    	vector<string>phones;
    };
    
    void test10()
    {
    
    	string line, word;	//分别保存来自输入的一行和单词
    	vector<PersonInfo> people;	//保存来自输入的所有记录
    	//逐行从输入读物数据,直至cin遇到文件尾(或其它错误)
    	while (getline(cin, line))
    	{
    		PersonInfo info;	//创建一个保存此记录数据的对象
    		istringstream record(line);	//将记录绑定到刚读入的行
    		record >> info.name;	//读取名字
    		while (record >> word)	//读取电话号码
    			info.phones.push_back(word);	//保持它们
    		people.push_back(info);	//将此记录追加到people末尾
    	}
    
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ])?(\ d{3})([-. ]?)(\ d{4})";
    	regex r(phone);	//regex对象,用于查找我们的模式
    	smatch results;	//定义一个对象保存搜索结果
    	for (const auto& entry : people)	//对people中每一项
    	{
    		ostringstream formatted, badNums;	//每个循环步创建的对象
    		for (const auto& nums : entry.phones)	//对每个电话号码
    		{
    			regex_search(nums, results, r);
    			if (!valid(results))
    				badNums << " " << nums;	//将数的字符串形式存入badNums
    			else
    				//将格式化的字符串写入fromatted
    				formatted << " " << format(nums);
    		}
    
    		if (badNums.str().empty()) //没有错误的数
    			cout << entry.name << " " << formatted.str() << endl;
    		else
    			cerr << "input error: " << entry.name
    			<< " invalid number(s) " << badNums.str() << endl;
    	}
    }

练习17.22:重新编写该电话号码程序以使其可在各组成部分间插入任意数量的空格

复制代码
    "(\ ()?(\ d{3})(\ ))?([-. ]|(\ s)*)?(\ d{3})([-. ]|(\ s)*)?(\ d{4})"

17.23

复制代码
    string pattern ="(\ d{5})([-])?(\ d"{4})?)";

17.3.4使用regex_replace

用于替换一个正则表达式

复制代码
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ]?(\ d{3})([-. ])?(\ d{4}))";
    
    	regex r(phone); //regex对象,用于查找我们的模式
    
    	string fmt = "$2.$5.$7 "; //将号码格式改为ddd.ddd.ddd
    	string fmt2 = "$2.$5.$7 ";
    	string number = "(908) 555-1800";
    
    	
    	cout << regex_replace(number, r, fmt) << endl;
    	cout << regex_replace(number,r,fmt2,format_no_copy) << endl;
    
    	number = "(08)555-1800";
    	cout << regex_replace(number,r,fmt) << endl;
    	//format_no_copy不满足条件就不显示了
    	cout << regex_replace(number, r, fmt2, format_no_copy) << endl;

练习17.24:自己版本的重排电话格式的程序

复制代码
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ]?(\ d{3})([-. ])?(\ d{4}))";
    
    	regex r(phone); //regex对象,用于查找我们的模式
    
    	string fmt = "$2.$5.$7 "; //将号码格式改为ddd.ddd.ddd
    	string fmt2 = "$2.$5.$7 ";
    
    	string s;
    	while (getline(cin,s) )
    	{
    		cout << regex_replace(s,r,fmt,format_no_copy) << endl;
    	}

17.25 电话号码程序 只输出每个人的第一个电话号码

复制代码
    	string phone = "(\ ()?(\ d{3})(\ ))?([-. ]?(\ d{3})([-. ])?(\ d{4}))";
    
    	regex r(phone); //regex对象,用于查找我们的模式
    
    	string fmt = "$2.$5.$7 "; //将号码格式改为ddd.ddd.ddd
    	string fmt2 = "$2.$5.$7 ";
    
    	string s;
    	while (getline(cin,s) )
    	{
    		s=regex_replace(s, r, fmt, format_no_copy);
    
    		sregex_iterator it(s.begin(), s.end(), r);
    		cout << it->str() << endl;
    	}

17.26 不会
代码https://zhuanlan.zhihu.com/p/361893659

17.27

复制代码
    string fmt ="$1-$3";

全部评论 (0)

还没有任何评论哟~