文本处理神器是什么?
我们非常重视原创文章,为尊重知识产权并避免潜在的版权问题,我们在此提供文章的摘要供您初步了解。如果您想要查阅更为详尽的内容,访问作者的公众号页面获取完整文章。
一、前言
花了一整天时间 ,系统性学了一遍正则表达式,相当不错,分享给大家,大家可以收藏备忘,需要的时候找出来查询使用就行。
个人体会,正则表达式不难,使用的时候在网上找找案例就行,但是如果你对他有全局了解,你就会发现,在未来使用和查找都会达到事半功倍的效果。
二、正则表达式是什么,有什么用
正则表达式(Regular Expression),简称 RE。在编程语言中,正则常常用来简化文本处理的逻辑。正则是一个非常强大的文本处理工具,它的应用极其广泛。我们可以利用它来校验数据的有效性,比如用户输入的手机号和邮箱是不是符合规则;也可以从文本中提取想要的内容,比如从网页中抽取数据;还可以用来做文本内容替换和切割,从而得到我们想要的内容。
三、正则表达式的构成
正则表达式主要由元字符构成, \d,它在正则中不代表 \ (反斜杠) 加字母 d,而是代表任意数字,这种表示特殊含义的字符表示,就是元字符。正则表达式中,元字符非常多,我们可以把元字符大致分成5类,分别是表示单个特殊字符的,表示空白符的,表示次数的量词,表示某个范围的,另外还有表示断言的.
1. 特殊单字符:
英文的点(.)表示换行以外的任意单个字符,
\d 表示任意单个数字,
\w 表示任意单个数字或字母或下划线,
\s 表示任意单个空白符。
另外,还有与之对应的三个 \D、\W 和 \S,分别表示着和原来相反的意思。
2. 空白符:大部分场景使用 \s 就可以满足需求,\s 代表任意单个空白符号。
\r回车符
\n 换行符
\f 换页符
\t 制表符
\v垂直制表符
3. 量词:
英文的星号(*): 0 到多次
加号(+): 1 到多次,
问号(?): 0 到 1 次,
?:0到1次、
{m}:出现m次
{m,}:出现至少m次
{m,n}: m 到 n 次。
4. 范围:在正则表达式中,表示范围的符号有四个分类。
管道符号,我们用它来隔开多个正则,表示满足其中任意一个就行,比如 ab|bc 能匹配上 ab,也能匹配上 bc,在正则有多种情况时,这个非常有用。
中括号[]代表多选一,可以表示里面的任意单个字符,所以任意元音字母可以用 [aeiou] 来表示。另外,中括号中,我们还可以用中划线表示范围,
[a-z] 可以表示所有小写字母。
脱字符(^),表示非,不能是里面的任何单个元素。
5.断言:^ 和 $ 符号
四、正则表达式的三种模式
正则中的三种模式,贪婪匹配、非贪婪匹配和独占模式。
贪婪模式(Greedy):简单说就是尽可能进行最长匹配。表示次数的量词默认是贪婪的,在贪婪模式下,会尝试尽可能最大长度去匹配。
非贪婪模式(Lazy):尽可能进行最短匹配。
我们可以在量词后面加上英文的问号 (?),将贪婪模式变成非贪婪模式呢?。
独占模式(Possessive)
不管是贪婪模式,还是非贪婪模式,都需要发生回溯才能完成相应的功能。独占模式,它类似贪婪匹配,但匹配过程不会发生回溯,因此在一些场合下性能会更好。
独占模式和贪婪模式很像,独占模式会尽可能多地去匹配,如果匹配失败就结束,不会进行回溯,这样的话就比较节省时间。具体的方法就是在量词后面加上加号(+)。需要注意的是 Python 和 Go 的标准库目前都不支持独占模式,会报错。
回溯:
regex = “xy{1,3}z”
text = “xyyz”
在匹配时,y{1,3}会尽可能长地去匹配,当匹配完 xyy 后,由于 y 要尽可能匹配最长,即三个,但字符串中后面是个 z 就会导致匹配不上,这时候正则就会向前回溯,吐出当前字符 z,接着用正则中的 z 去匹配。
如果我们把这个正则改成非贪婪模式,如下:
regex = “xy{1,3}?z”
text = “xyyz”
由于 y{1,3}? 代表匹配 1 到 3 个 y,尽可能少地匹配。匹配上一个 y 之后,也就是在匹配上 text 中的 xy 后,正则会使用 z 和 text 中的 xy 后面的 y 比较,发现正则 z 和 y 不匹配,这时正则就会向前回溯,重新查看 y 匹配两个的情况,匹配上正则中的 xyy,然后再用 z 去匹配 text 中的 z,匹配成功。
五、正则表达式的分组
分组与编号
括号在正则中可以用于分组,被括号括起来的部分“子表达式”会被保存成一个子组。
那分组和编号的规则是怎样的呢?其实很简单,用一句话来说就是,第几个括号就是第几个分组。
假设时间格式是 2020-05-10 20:23:05 。
日期分组编号是 1,时间分组编号是 5,年月日对应的分组编号分别是 2,3,4,时分秒的分组编号分别是 6,7,8。
下面以Python3 为例,给出一个示例。
>>> import re
>>> test_str = "2020-05-10 20:23:05"
>>> regex = r"((\d{4})-(\d{2})-(\d{2})) ((\d{2}):(\d{2}):(\d{2}))"
>>> subst = r"日期\1 时间\5 \2年\3月\4日 \6时\7分\8秒"
>>> re.sub(regex, subst, test_str)
'日期2020-05-10 时间20:23:05 2020年05月10日 20时23分05秒'
六、正则中的匹配模式(Match Mode)
所谓匹配模式,指的是正则中一些改变元字符匹配行为的方式,比如匹配时不区分英文字母大小写。常见的匹配模式有 4 种,分别是不区分大小写模式、点号通配模式、多行模式和注释模式。
不区分大小写模式,它可以让整个正则或正则中某一部分进行不区分大小写的匹配。
点号通配模式也叫单行匹配,改变的是点号的匹配行为,让其可以匹配任何字符,包括换行。
多行匹配说的是 ^ 和 $ 的匹配行为,让其可以匹配上每行的开头或结尾。
注释模式则可以在正则中添加注释,让正则变得更容易阅读和维护。
不区分大小写模式(Case-Insensitive)
不分大小写的英文是 Case-Insensitive,那么对应的模式标识就是 I 的小写字母 i,所以不区分大小写的 cat 就可以写成 (?i)cat。
修饰符如果在括号内,作用范围是这个括号内的正则,而不是整个正则;
点号通配模式(Dot All)
正则中提供了一种模式,让英文的点(.)可以匹配上包括换行的任何字符。
这个模式就是点号通配模式,有很多地方把它称作单行匹配模式,但这么说容易造成误解,毕竟它与多行匹配模式没有联系,因此在课程中我们统一用更容易理解的“点号通配模式”。
单行的英文表示是 Single Line,单行模式对应的修饰符是 (?s),我还是选择用 the cat 来给你举一个点号通配模式的例子。如下图所示:
需要注意的是,JavaScript 不支持此模式,那么我们就可以使用前面说的[\s\S]等方式替代。在 Ruby 中则是用 Multiline,来表示点号通配模式(单行匹配模式),我猜测设计者的意图是把点(.)号理解成“能匹配多行”。
多行匹配模式(Multiline)
通常情况下,^匹配整个字符串的开头,$ 匹配整个字符串的结尾。多行匹配模式改变的就是 ^ 和 $ 的匹配行为。
多行模式的作用在于,使 ^ 和 $ 能匹配上每行的开头或结尾,我们可以使用模式修饰符号 (?m) 来指定这个模式。
这个模式有什么用呢?在处理日志时,如果日志以时间开头,有一些日志打印了堆栈信息,占用了多行,我们就可以使用多行匹配模式,在日志中匹配到以时间开头的每一行日志。
值得一提的是,正则中还有 \A 和 \z(Python 中是 \Z) 这两个元字符容易混淆,\A 仅匹配整个字符串的开始,\z 仅匹配整个字符串的结束,在多行匹配模式下,它们的匹配行为不会改变,如果只想匹配整个字符串,而不是匹配每一行,用这个更严谨一些。
注释模式(Comment)
正则中注释模式是使用 (?#comment) 来表示。
比如我们可以把单词重复出现一次的正则 (\w+) \1 写成下面这样,这样的话,就算不是很懂正则的人也可以通过注释看懂正则的意思。
(\w+)(?#word) \1(?#word repeat again)
七、正则表达式断言
什么是断言呢?简单来说,断言是指对匹配到的文本位置有要求。这么说你可能还是没理解,我通过一些例子来给你讲解。你应该知道 \d{11} 能匹配上 11 位数字,但这 11 位数字可能是 18 位身份证号中的一部分。再比如,去查找一个单词,我们要查找 tom,但其它的单词,比如 tomorrow 中也包含了 tom。
也就是说,在有些情况下,我们对要匹配的文本的位置也有一定的要求。为了解决这个问题,正则中提供了一些结构,只用于匹配位置,而不是文本内容本身,这种结构就是断言。常见的断言有三种:单词边界、行的开始或结束以及环视。
单词的边界、行的开始或结束、环视。
单词的边界是使用 \b 来表示,这个比较简单。而多行模式下,每一行的开始和结束是使用 ^ 和 $ 符号。如果想匹配整个字符串的开始或结束,可以使用 \A 和 \z,它们不受匹配模式的影响。
最后就是环视,它又分为四种情况:肯定逆向环视、否定逆向环视、肯定顺序环视、否定顺序环视。在使用的时候记住一个方法:有左尖括号代表看左边,没有尖括号是看右边,而感叹号是非的意思。
八、正则表达式转义
转义字符(Escape Character)。它在维基百科中是这么解释的:在计算机科学与远程通信中,当转义字符放在字符序列中,它将对它后续的几个字符进行替代并解释。通常,判定某字符是否为转义字符由上下文确定。转义字符即标志着转义序列开始的那个字符。
转义序列通常有两种功能。第一种功能是编码无法用字母表直接表示的特殊数据。第二种功能是用于表示无法直接键盘录入的字符(如回车符)。
如何在正则中正确表示“反斜杠”呢?答案是写四个反斜杠。
九、结语
上面是本人对正则表达式的知识梳理,仅供参考和辅助理解,资料来源于网络和自己的总结,如果对你有帮助,烦请星标收藏,关注、转发,如有任何问题,请留言或加我微信入群,我们一起探讨,一起持续构建数据治理体系。
想要了解更多内容?
持续完善数据治理实战体系,数据仓库、标签、指标体系,实现业务数字化,数字资产化,资产业务化,资产资本化;回归业务场景的数字化案例才最具参考价值,最容易理解和借鉴的。关注我,和您一起终身学习。
白皮书上线