看了下人工智能关键词下的人气关键词,基本上提到机器学习、大数据的薪资相对比较高。
虽然我自己的专业就是人工智能的归纳定理自动证明,不过由于我的研究是前瞻的、理论的,未来50年也许能落地,到时候变成香饽饽倒是可以预见。
然而到那之前还是得生活啊。顺应时代,准备对一些能落地的技术进行学习,关键词:
Hadoop, TensorFlow不过今天想要先把正则表达式的部分复习、整理一下(想起了学自动机的日子),供以后查阅,
捣鼓vim脚本
概要
深入浅出地介绍正则表达式
正则表达式速查表
关于正则表达式
正则表达式(regular expression,regex,正規表現)是指使用一个字符串来表达字符串集合的一种方式。
一个简单的例子:
^[0-9]+abc$
^符号用来定义字符串开始位置。[0-9]意思是匹配一位数字,而后面紧跟着的+则表示可匹配一位或多位。abc匹配字母abc,而最后一个符号$则定义了字符串结束位置。
因此该正则表达式将会匹配字符串123abc或者43abc等等。
需要注意的是,如果对多行字符串如123abc\n43abc进行匹配,将返回空。
再来一个例子:
^[0-9a-z_-]{3,15}$
该正则表达式可以匹配任何长度在3到15之间仅仅包含字母、数字、下划线_和连字符号-的字符串。
有了以上两个例子,我们可以给出正则表达式的具体定义:
正则表达式是由普通字符(如a-z,A-Z)和特殊字符(元字符)组成的文字模式。
普通字符
普通字符是指没有显式指定为元字符的所有可打印字符和不可打印字符。
普通字符包括:所有大写和小写字母,数字,所有标点符号和一些其他符号。
不可打印字符
不可打印字符意味着它们将会被转义:
| 字符 | 描述 |
|---|---|
| \cx | 匹配一个由x指明的控制符。例如,\cm匹配为Ctrl+M(回车符)。x的值必须为a-z或A-Z,否则会直接被认为是原义字符’c’ |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM |
| \s | 匹配任何种类的一个空白字符,包括空格,制表符,换页符等。等价于[ \f\n\r\t\v],注意 Unicode 正则表达式会匹配全角空格符。 |
| \S | \s的反义,匹配任何一个非空白字符。等价于 [^ \f\n\r\t\v] |
| \t | 匹配一个制表符。等价于 \x09 和 \cI |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK |
特殊字符
特殊字符是指具有特殊意义的字符。如需匹配它们需要使用\进行转义。
| 字符 | 描述 |
|---|---|
| $ | 匹配字符串的结尾位置。如果开启Multiline属性,那也会匹配换行处\r\n,\n,\r |
| () | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用 |
| * | 匹配前面的子表达式0次或多次 |
| + | 匹配前面的子表达式1次或多次 |
| . | 匹配除换行符之外的任何单字符 |
| [ | 标记一个中括号表达式的开始 |
| ? | 匹配前面的子表达式0次或一次,或指明一个非贪婪限定符 |
| \ | 转义符,将下一个字符标记为一个不可打印字符、或一个原义字符、或一个向后引用、或一个八进制转义符。 |
| ^ | 匹配字符串的开始位置;当在方括号[]中被使用时,则表示非这些字符的集合。例如,[abc]将匹配a或b或c,[^abc]将匹配任何非a、b、c的一位字符 |
| { | 标记限定符表达式的开始 |
限定符
限定符是由特殊字符组成,用来指定正则表达式的一个组件必须要重复多少次才能满足匹配,分为如下6种:
| 字符 | 描述 |
|---|---|
| * | 匹配前面的子表达式0次或多次。例如:zo*能匹配"z","zo","zoo", 等价于zo{0,} |
| + | 匹配前面的子表达式1次或多次。例如:zo+能匹配"zo","zoo"但不匹配"z", 等价于zo{1,} |
| ? | 匹配前面的子表达式0次或1次。例如:do(es)?能匹配"do"或"does", 等价于do(es){0,1} |
| {n} | 匹配前面的子表达式n次(n是一个非负整数)。例如:o{2}会匹配"cool"里的"oo",但不会匹配"fox"的"o"或"coool"里的"ooo" |
| {n,} | 匹配前面的子表达式至少n次(n是一个非负整数)。例如:o{2,}会匹配"cool"、"coool"里的"oo"和"ooo",但不会匹配"fox"的"o"。'{0,}’等价于’*’, ‘{1,}’等价于’+’ |
| {n,m} | 匹配前面的子表达式k次(n和m都是非负整数, n<=m, n<=k<=m)。例如:o{2,3}会匹配"cooool"里的前3个"ooo"。'{0,1}’等价于’?’ |
例子:
可以使用如下正则表达式来匹配章节编号
Chapter [1-9][0-9]*
该表达式将会匹配Chapter n,其中n>=1(从第一章开始的所有章节)。
如果章节被限定在99以内,尝试使用如下表达式
Chapter [0-9]{1,2}
不过很显然的,这样做同时也会匹配Chapter 0;于是有了如下的版本:
Chapter [1-9][0-9]?
//等价
Chapter [1-9][0-9]{0,1}
不过要注意的是如果章节超过100,将会仅匹配前两位。
限定符的非贪婪匹配
限定符*,+,?默认是贪婪匹配的,也就是会尽量匹配更多的字符。
比如:
<h1>这是一个例子</h1>
如果使用<.*>进行匹配,会得到
<h1>这是一个例子</h1>
而如果在这之后加上?,变成<.*?>进行匹配的话,将会单独匹配到首标签<h1>。
这是因为<h1>是第一个满足条件的字符串,但要注意这并不说明<.*?>无法匹配尾标签</h1>。
如果仅仅想要匹配首标签<h1>,可以使用<\w+?>或<\w+>来进行匹配。
定位符
定位符可以将正则表达式定位到一些具体的位置,如字符串的开头或结尾,或者单词的边界。
| 字符 | 描述 |
|---|---|
| ^ | 定位到字符串开始位置。如果multiline属性被启用,那么也会匹配换行符\n,\r之后的位置。 |
| $ | 定位到字符串结束位置。如果multiline属性被启用,那么也会匹配换行符\n,\r之前的位置。 |
| \b | 定位到单词的边界。即空格与字之间的位置 |
| \B | 定位到非单词的边界位置 |
注意,这些定位符都是无法和限定符同用的(比如:^*是错误的表达式),因为没有意义。
例子:
章节会在该行的行首,因此可以加入^进行定位:
^Chapter [1-9][0-9]{0,1}
同时由于章节出现的那一行不会再有其他字符,所以它也应该是该行最后的字符串,所以在后面可以加入$进行定位:
^Chapter [1-9][0-9]{0,1}$
关于边界定位符\b的使用,也很直观,比如:\bCha就能匹配Chapter里的Cha,ter\b能匹配Chapter里的ter;
边界定位符\B则会匹配所有非边界位置,比如:\Bapt\B会匹配Chapter里的apt,但并不会匹配aptitude里的apt。
选择
使用()将所有选择项都包含起来,并且使用|隔开,注意默认情况下每一项都会被缓存。如果不希望被缓存,可以在该括号内的开头使用?:来取消该项的缓存。
而在?后面加上的?=,?!,?<=,?<!四种表达有更特殊的含义,用下面的例子来说明。
例子用字符串:
java6 java7
正向肯定预查?=,使用java(?=6)会匹配第一个java6 java7,意味着匹配后面跟着6的java;
正向否定预查?!,使用java(?!6)会匹配第二个java6 java7,意味着匹配后面不跟着6的java;
逆向肯定预查?<=,使用(?<=j)a会匹配到两个a:java java,意味着匹配前面有j的a;
逆向否定预查?<!,使用(?<!j)a会匹配到两个a:java java,意味着匹配前面没有j的a;
反向引用缓存
使用圆括号()可以将其匹配到的子串进行缓存,按照括号从左到右的顺序,一共有从1号开始到99号缓存区。
每个缓存区可以使用\n来进行访问,其中1<=n<=99。
利用这个功能,可以查找两个相同的、相邻的单词的匹配。
例子:
要查找的字符串:
Locate locate and filter filter the duplicated duplicated substrings.
使用如下正则表达式:
\b([a-z]+) \1\b
可以得到
filter filter
如果开启全局匹配模式,则可以得到
filter filter
duplicated duplicated
如果在开启全局匹配的同时再开启忽略大小写,则可以得到
Locate locate
filter filter
duplicated duplicated
利用缓存区,可以轻松地分割URL。比如:
https://capital-g.cc:443/#/blog
使用如下表达式进行分割匹配:
(^\w+)://(\w[^:/]+)(:\d+)?([^ ]+$)
匹配结果:
Found value: https://capital-g.cc:443/#/blog
Stored value: https
Stored value: capital-g.cc
Stored value: :443
Stored value: /#/blog
正则表达式速查
| 符号 | 意义 |
|---|---|
| \ | 转义符,将下一个字符标记为一个不可打印字符、或一个原义字符、或一个向后引用、或一个八进制转义符。 |
| ^ | 匹配字符串的开始位置;当在方括号[]中被使用时,则表示非这些字符的集合。例如,[abc]将匹配a或b或c,[^abc]将匹配任何非a、b、c的一位字符 |
| $ | 匹配字符串的结尾位置。如果开启Multiline属性,那也会匹配换行处\r\n,\n,\r |
| * | 匹配前面的子表达式0次或多次。例如:zo*能匹配"z","zo","zoo", 等价于zo{0,} |
| + | 匹配前面的子表达式1次或多次。例如:zo+能匹配"zo","zoo"但不匹配"z", 等价于zo{1,} |
| ? | 匹配前面的子表达式0次或一次,或指明一个非贪婪限定符 |
| {n} | 匹配前面的子表达式n次(n是一个非负整数)。例如:o{2}会匹配"cool"里的"oo",但不会匹配"fox"的"o"或"coool"里的"ooo" |
| {n,} | 匹配前面的子表达式至少n次(n是一个非负整数)。例如:o{2,}会匹配"cool"、"coool"里的"oo"和"ooo",但不会匹配"fox"的"o"。'{0,}’等价于’*’, ‘{1,}’等价于’+’ |
| {n,m} | 匹配前面的子表达式k次(n和m都是非负整数, n<=m, n<=k<=m)。例如:o{2,3}会匹配"cooool"里的前3个"ooo"。'{0,1}’等价于’?’ |
| . | 匹配除换行符之外的任何单字符。如需要匹配换行符可以使用(. |
| (regex) | 匹配regex并缓存该结果,在表达式内引用使用\num, 在结果引用使用$num, 99>=num>=1 |
| (?:regex) | 匹配regex但不缓存该结果,引用方式同上 |
| str(?=regex) | 正向预查。匹配具有regex后缀的str。例如:对于"java6 java7",使用java(?=6)来匹配前一个"java" |
| str(?!regex) | 否定正向预查。匹配不具有regex后缀的str。例如:对于"java6 java7",使用java(?!6)来匹配后一个"java" |
| str(?<=regex) | 逆向预查。匹配具有regex前缀的str。例如:对于"java",使用(?<=j)a来匹配前一个"a" |
| str(?<!regex) | 否定逆向预查。匹配不具有regex前缀的str。例如:对于"java",使用(?<!j)a来匹配后一个"a" |
| a|b | 匹配a或者b |
| [abc] | 匹配[]中任意一个字符。例如:对于"carry",使用[abc]可以匹配到"a" |
| [^abc] | 不匹配[]中任意一个字符。例如:对于"carry",使用[^abc]可以匹配到"r","r","y" |
| [a-z] | 匹配小写字母a-z之间的字符。 |
| [^a-z] | 匹配非小写字母a-z之间的字符。 |
| \b | 定位到单词的边界。即空格与字之间的位置 |
| \B | 定位到非单词的边界位置 |
| \d | 匹配一个数字字符,等价于[0-9] |
| \D | \d的反义,匹配一个非数字字符,等价于[^0-9] |
| \s | 匹配任何种类的一个空白字符,包括空格,制表符,换页符等。等价于[ \f\n\r\t\v],注意 Unicode 正则表达式会匹配全角空格符。 |
| \S | \s的反义,匹配任何一个非空白字符。等价于 [^ \f\n\r\t\v] |
| \w | 匹配数字、字母和下划线。等价于[a-zA-Z0-9_] |
| \W | \w的反义,匹配任何一个非数字、字母或下划线。等价于[^a-zA-Z0-9_] |
| \cx | 匹配一个由x指明的控制符。例如,\cm匹配为Ctrl+M(回车符)。x的值必须为a-z或A-Z,否则会直接被认为是原义字符’c’ |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM |
| \t | 匹配一个制表符。等价于 \x09 和 \cI |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK |
| \xNum | 匹配十六进制数据。Num为十六进制数据,支持ASCII码 |
| \Num | 表达式内引用Num号缓存,1<=Num<=99,如果不存在该缓存,则当做八进制处理 |
| \uNum | 匹配一个Unicode码。 |