Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

正则表达式的拓展 #57

Open
ZhangZhiyuan-2021 opened this issue Jun 14, 2022 · 1 comment
Open

正则表达式的拓展 #57

ZhangZhiyuan-2021 opened this issue Jun 14, 2022 · 1 comment

Comments

@ZhangZhiyuan-2021
Copy link

ZhangZhiyuan-2021 commented Jun 14, 2022

正则表达式的拓展应用

正则表达式(Regular Expression)利用普通字符和元字符构成匹配某个句法规则的字符串,常被用来进行大量的数据处理,在课程中我们接触到了一些关于正则表达式的基本用法。这里我们来接触一些正则表达式的拓展用法。

在进行学习的时候,可以在这个网址来检验你所写出的正则表达式作用。


正则表达式的非捕获分组

(?:pattern)表示非捕获分组,和上课提到的捕获分组的惟一的区别在于,非捕获分组匹配的值并不会被保存下来,这常常用来搜索一些只有部分不相同的整体。比如,我们可以使用(?:pattern)|字符来组合一个整体:part(?:y|ies)就等价于party|parties,而使用part(y|ies)虽然可以达到同样的效果,但是会捕获一个无用的分组y或者ies,这是没有意义的。


正则表达式的预查

预查可以分为四部分,分别是正向和反向的肯定以及否定预查。预查的特点就是,这是一个非获取匹配,与刚才介绍到的非捕获分组十分类似,但区别在于,预查是不消耗字符的,也就是说这段字符可以继续被正则表达式的其他部分匹配。


正向肯定预查(?=pattern)

对将要捕获的字符串做提前的检查,只捕获符合要求的,比如Version(?=1.0|1.1)可以匹配Version1.0,但不能匹配Version2.0。预查不消耗字符,在任何匹配的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。

正向否定预查(?!pattern)

与正向肯定预查类似,但要求完全相反。还是以上述例子,Version(?!1.0|1.1),这时,它可以匹配Version2.0,但不能匹配Version1.0

反向肯定预查(?<=pattern)

与正向肯定预查类似,只是方向相反。比如(?<=New |Old )Version可以匹配New Version,但不能匹配Formal Version

反向否定预查(?<!pattern)

与正向否定预查类似,只是方向相反。比如(?!=New |Old )Version可以匹配Formal Version,但不能匹配New Version


我们认为,正向和反向预查的区别在于,我们前提假定哪部分字符串是“真实的”。比如在刚才的四个例子中,我们认为单词Version是必然存在的,检查的只是附加在Version上的不同值。

在上次的作业中,我们处理数据时对password进行了检查,要求是8~20位的数字和字母,不能全是数字或字母。

我们可以使用如下代码进行查验:

regex get_password(R"+=("password"[\s]*:[\s]*"((?![0-9]+")(?![A-Za-z]+")[0-9A-Za-z]{8,20})")+=");
/*
	R"+=(xxx)+="是原生字符串的另一种形式,在"和(与)和"中间添加相同的字符串,使得原生字符串中的)"不会被认为是结尾。
	[\s]*是上次作业要求中,为了匹配在双引号外面的不确定个数空格符。
*/

我们已经确定在需要否定预查的(?![0-9]+")(?![A-Za-z]+")前面的"是确定存在的,而后方的密码是我们在预查之后能否捕获的,所以我们选择正向否定预查。


正则表达式的后向引用

在课堂上我们介绍了分组的捕获,分组0表示整个正则表达式,后面的1、2等表示被捕获的分组。

后向引用被用来重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。

([\w]+)[\s]*:[\s]*\1 is a word可以用来匹配重复的单词。这个表达式s首先将一个单词捕获到编号为1的分组中,然后是一些空白符([\s]*)以及其他描述,最后是分组1中捕获的内容\1和后续匹配。

分组也可以被我们自己命名,指定一个分组的组名可以使用语法:(?<Word>[\w]+),或者将<>换成''(?'Word'[\w]+)),这样就把[\w]+的组名指定为Word了。想要引用这个分组捕获的内容,我们可以使用\k<Word>,所以上一个例子也可以写成这样:(?<Word>[\w]+)[\s]*:[\s]*\k<Word> is a word


正则表达式的贪婪与懒惰

*+?是我们常用的用来表示重复的元字符,其中*可以表示重复任意次,+可以表示重复1次及以上,?可以表示重复0次或1次,与之类似的还有{n,m}{n,}等。

我们在使用这些元字符时,默认的行为是贪婪匹配,也就是匹配尽可能多的字符。举个例子,如果我们使用p.*e来匹配procedure,会捕获到整个字符串procedure而不是proce

如果在元字符后加?,使其变成*?+???{n,m}?{n,}?等,就会变为懒惰匹配,匹配尽可能少的字符。


特别的,在正则表达式中,有另一条规则,比贪婪/懒惰规则的优先级更高:最先开始的匹配拥有最高的优先权。因此,我们在使用a.*?匹配aaabbaabab的时候,会得到aaab而不是ab

@Yu-Shi
Copy link
Member

Yu-Shi commented Jul 4, 2022

OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants