正则表达式编程

编程中经常会出现对字符串的处理,自己编写处理程序通常是低效的,也是一种重复造轮子的行为,如果掌握使用正则表达式处理字符串,可以极大提高编程效率。

正则表达式的语法就不作说明,这里主要类比在c++和python中如何使用正则表达式进行编程。

match 匹配

match 函数通常需要两个参数,patterns,其中 pattern 为正则表达式,s 表示待匹配字符串,返回值在c++和python中并不相同。下面是两个功能类似的例子:

  • c++ 版
#include <iostream>
#include <regex>
#include <string>

using namespace std;

int main(int argc, char* argv[]){
    string fnames[] = {"foo.txt", "bar.txt", "test.txtx", "0a.txt", "AAA.txt"};
    regex txt_regex("[a-z]+\\.txt");
    for(string& fname: fnames){
        cout << fname << ": " << regex_match(fname, txt_regex) << endl;
    }
    return 0;
}

输出为

foo.txt: 1
bar.txt: 1
test.txtx: 0
0a.txt: 0
AAA.txt: 0
  • python 版
import re

fnames = ["foo.txt", "bar.txt", "test.txtx", "0a.txt", "AAA.txt"]

txt_regex = re.compile(r"[a-z]\.txt")
txt_regex = re.compile("[a-z]+\\.txt")
for fname in fnames:
    print(f"{fname}: {txt_regex.match(fname)}")

输出为:

foo.txt: <_sre.SRE_Match object; span=(0, 7), match='foo.txt'>
bar.txt: <_sre.SRE_Match object; span=(0, 7), match='bar.txt'>
test.txtx: <_sre.SRE_Match object; span=(0, 8), match='test.txt'>
0a.txt: None
AAA.txt: None

对比 c++ 和 python 中 match 的用法,可以看出c++返回的是一个 bool类型的,而python如果能够匹配,就返回匹配实例,否则返回None。而且c++默认是对这个字符串匹配,而python只要前一部分能够匹配就认为匹配成功。

c++ 匹配到的结果可以通过传入类型为 smatch 的参数获取,例如传入的参数名为 sm,则 sm.length() 返回匹配的字符串长度,sm.size() 为捕获的变量数,其中第一个为匹配到的整个字符串,之后为正则表达式中用()捕捉到的内容,捕捉到的内容可以用类似 sm[1] 获取,也可以用 sm.format("... $1 ...") 直接用于格式化。

c++ 的 regex_match 的其他用法(参考: <https://blog.csdn.net/mycwq/article/details/18838151

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

using namespace std;

int main(){
    string s = "xsubject";
    regex e("(sub)(.*)");
    if(regex_match(s, e)){
        cout << "string object matched" << endl;
    }
    // 部分匹配
    if(regex_match(s.begin()+1, s.end(), e)){
        cout << "range matched" << endl;
    }
    // 获取匹配结果
    smatch sm;
    if(regex_match(s.cbegin()+1, s.cend(), sm, e)){
        cout << sm.str() << endl;
        for(int i=0; i<sm.size(); ++i){
            cout << "\t" << i << ": " << sm[i] << endl;
        }
    }
    return 0;
}

输出结果为:

range matched
subject
        0: subject
        1: sub
        2: ject

search 搜索

match 和 search 的主要区别:match 是全词匹配,而 search 是搜索其中匹配的字符串。

  • c++
#include <iostream>
#include <regex>
#include <string>
using namespace std;

int main(){
    string s("this subject has a submarine as subsequence");
    smatch m;
    regex e("\\b(sub)([^ ]*)");
    while(regex_search(s, m, e)){
        for(auto x=m.begin(); x!=m.end(); x++){
            cout << x->str() << ", ";
        }
        cout << m.format(" --> ([^ ]*) match $2") << endl;
        // 等价于
        // cout << " --> ([^ ]*) match " << m[2] << endl;        
        s = m.suffix().str();
    }
    return 0;
}

输出为:

subject, sub, ject, --> ([^ ]*) match ject
submarine, sub, marine, --> ([^ ]*) match marine
subsequence, sub, sequence, --> ([^ ]*) match sequence

等价的 python 代码为:

import re

s = "this subject has a submarine as subsequence"
e = re.compile("\\b(sub)([^ ]*)")

bg_pos = 0
m = e.search(s, bg_pos)
while m:
    print(m.group(), end=", ")
    for ts in m.groups():
        print(ts, end=", ")
    print("--> ([^ ]*) match", m[2])
    bg_pos = m.end()
    m = e.search(s, bg_pos)

replace 替换

  • c++
#include <iostream>
#include <regex>
#include <string>
using namespace std;

int main(){
    string s = "This is string, that is right;";
    regex e("th([^\\s]+)", regex::icase);
    string news = regex_replace(s, e, "[$1]");
    cout << s << endl;
    cout << news << endl;
}

输出为:

This is string, that is right;
[is] is string, [at] is right;

等价的 python 代码为:

import re

s = "This is string, that is right;"
e = re.compile("th([^\\s]+)", re.RegexFlag.IGNORECASE)

print(s)
print(e.sub(lambda mt: "[%s]" %(mt[1]), s))

总结

下面用两段代码对正则表达式在c++和python中进行总结:

  • c++
#include <iostream>
#include <regex>
#include <string>
using namespace std;

int main(){
    string s("this is me, that\tis you!");
    regex ex("\\bth([^\\s]+)");
    smatch mt;
    // 匹配
    if(regex_match(s.cbegin(), s.cbegin()+3, mt, ex)){
        cout << mt.str() << endl;
    }
    string s2 = s;
    // 搜索
    while(regex_search(s2, mt, ex)){
        cout << mt[1] << endl;
        s2 = mt.suffix();
    }
    // 替换
    s2 = regex_replace(s, ex, "$1");
    cout << s2 << endl;
}
  • python
import re

s = "this is me, that\tis you!"
ex = re.compile("\\bth([^\\s]+)")

mt = ex.match(s, 0, 3)
print(mt.group())

bg_pos = 0
mt = ex.search(s, bg_pos)
while mt:
    print(mt[1])
    bg_pos = mt.end()
    mt = ex.search(s, bg_pos)

print(ex.sub(lambda m:m[1], s))

上述两段代码的输出都为:

thi
is
at
is is me, at    is you!

练习

下面是网易的一道笔试题,用c++完成,题目要求为解析简易版的markdown文档,文档的要求为:

  • ######、... 开头的行,去掉最前面的#;
  • +\t 开头的行,去掉最前面的 +t
  • 将超链接替换为其内容,例如将 abc[xxx](url.com) 替换为 abcxxx

c++实现代码为:

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


string decode_markdown(string s){
    // #、##、### 表示标题
    regex e_title("^(#+)");
    // +\t 表示list
    regex e_list("^\\+\\t");
    // []()表示超链接
    regex e_href("\\[([^\\]]*)\\]\\([^\\)]*\\)");
    string ret, line;
    istringstream sf(s);
    while(getline(sf, line)){
        string ns = regex_replace(line, e_title, "");
        ns = regex_replace(ns, e_list, "");
        ns = regex_replace(ns, e_href, "$1");
        ret += ns + "\n";
    }
    
    return ret;
}

int main(){
    string s("#hello\n##world\n+\tlist1\n+\tlist " \
        "[this is href](abc.com) suffix\nsome thing "\
        "[another ref](aaa.com) else\n");
    cout << decode_markdown(s) << endl;
}

输出为:

hello
world
list1
list this is href suffix
some thing another ref else

对应的python代码为:

import re

s = ("#hello\n##world\n+\tlist1\n+\tlist " +
        "[this is href](abc.com) suffix\nsome thing " +
        "[another ref](aaa.com) else\n")
result = ""
e_title = re.compile("^(#+)")
e_list = re.compile("\\+\\t")
e_href = re.compile("\\[([^\\]]*)\\]\\([^\\)]*\\)")
for line in s.split('\n'):
    ns = e_title.sub("", line)
    ns = e_list.sub("", ns)
    ns = e_href.sub(lambda mt:mt[1], ns)
    result += ns + '\n'
print(result)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第七章 正则表达式编程 什么叫知识,能指导我们实践的东西才叫知识。 学习一样东西,如果不能使用,最多只能算作纸上谈...
    凯睿看世界阅读 858评论 1 2
  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 7,230评论 0 99
  • 搞懂Python 正则表达式用法 Python 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一...
    厦热阅读 1,641评论 0 2
  • 现在Android的开发者基本上都使用Android Studio进行开发(如果你还在使用eclipse那也行,毕...
    CrazyLiuXP阅读 431评论 0 0
  • 西宁 上午塔尔寺 下午睡觉调整,傍晚去东关清真大寺 莫家街小吃街 马忠食府
    云裳灼煙阅读 165评论 0 1