欢迎光临散文网 会员登陆 & 注册

大忙人系列-程序猿在想什么 (三) 状态机与正则表达式

2020-01-20 19:12 作者:汐留楓Channel  | 我要投稿

一. 传说中的正则表达式

无论你和计算机沾不沾边,“正则表达式”这个词多多少少都会听过,而越是不了解,就越感觉这个词逼格很高。“正则”是什么东西?听上去挺洋气的,正看上去像正规,然后则呢...打则必死。

第一次碰见这玩意儿的时候还是当初学RMXP的时候(也是个上古的东西了)。想当年连程序都没写过就去学Ruby,而那翻译也鬼才把成员变量翻译成“实变量”(至少也应该是实例变量啊),搞了半天都不知道这到底是个什么鬼,为什么前面要加个at。在教程的结尾,写着“附录”“正则表达式”,深深地吸引着年幼的我。


点进去。


从头到尾是各种类字符通配符的列表。


这是个啥?!


二. 正则表达式&正规式

如果你学过编译原理那一定听说过正规式却又没听说过正则表达式...赶紧去学!学会前不要说自己是CS的XD。

这两者概念上似乎有微秒的不同但是本质却是一样的。个人认为,可以把正则表达式看为一种正规式,给定一个模式与一个字符串就可以查找字符串内模式出现的地方。而讨论这些,就不得不讨论状态机。


三. 状态机

状态机是现实事物运行规则抽象而成的一个数学模型。简单而言,就是用一些存储空间来表示当前的状态,然后每一次根据外部的数据或者情况改自己的状态。《ICS》里面举了两个例子,一个是篮球比赛的记分牌,还有一个是转盘密码锁。你都可以把所有可能的状态列举出来,然后根据不同的情况(进球了,或者扭入了一个密码)来变更整个系统的状态。状态机这个模型可以在很多地方使用,包括对一个模式的匹配,最直接的办法就是使用状态机。


四. NFA&DFA

假设现在已经有了一个模式,人肉去做匹配,最简单的就是一个一个看,和普通的字符串匹配有点相似。比如,要匹配ab或者ac,假设没有优化,0号状态就是初始状态,1号状态为0状态下读入a,2号为1号读b;3号为0号读a,4号为3号读c。这个样子,在0号状态计算机并不知道走哪条分支,只能随便走一个,等匹配到后面发现错了,就需要回溯,这就是NFA。

NFA比较直接,但是也比较简陋,需要回溯的话在匹配中会消耗大量资源,但是可以转成DFA(虽然也要不少资源算、转)。DFA就直接,每一步到下一个状态都是确定的。做法很简单,将NFA每个状态下每种输入会得到怎样的结果全部计算一遍。第一步当然是初始状态A0,把不经过任何字符或者经过epsilon(空字符)能到达的状态全部写出来,然后计算经过所有字符后能到达的状态A1 A2...An,然后再把所有的状态作输入,再经过一个字符,得到B(A1)1 B(A1)2...B(An)m。本质上则是提前把所有可能的回溯全部做了。


五. More about 正则表达式

(其实是在水字数)

很多要搜索的地方支持正则表达式搜索,当你对你要搜的东西比较印象比较模糊的时候可以用,会非常方便,比如VS,比如everything。当然,也可以用来处理爬虫爬回来的数据。有的时候,是真的为了快速匹配一些模式,所以要记下一些常用的通配符。


^ 匹配字符串开头

$ 匹配字符串结尾

上面两个很重要,比如你想匹配文件名的话写 .*\.pdf$ 专门指定要以.pdf结尾,而f后面啥也不能接,就可以用$,同理^表示要从开头开始匹配。


.

匹配任意字符,使用频率Max,就连上面那个那么简单的例子都跳脱不了这个符号


* 前面的字符/模式重复任意次(或者零次)

+ 前面的字符/模式重复任意次(一次及以上)

还是见第一个例子, .* 就表示任意字符重复任意次。注意,如果在这两个符号后面加上 ? 表示是惰性匹配,只要满足条件就匹配中,否则系统会尝试匹配尽可能长的串。

aaaaa与表达式 a+? 和 a+ 第一个只会匹配a,而第二个会匹配aaaaa


? 前面的字符/模式可有可无

do(es)? 匹配do或者does


[a-zA-Z] 匹配一个任意大小写字母

中括号表示匹配里面列举的任意一个字符


[^a-zA-Z] 与上面相反,匹配一个字母以外的字符

^放在前面表示匹配列举以外的



(?<=pattern)

(?=pattern)

一个前肯一个后肯。

(?<=Hello)hi(?=Bye)

匹配前有Hello后有Bye的hi


\ 万能的转义

当你感觉你用的字符可能不代表它本身的含义的时候,加上这个。

大忙人系列-程序猿在想什么 (三) 状态机与正则表达式的评论 (共 条)

分享到微博请遵守国家法律