正则表达式入门

正则表达式工作中一直在使用,但是没有系统的总结过,今天就从小白的角度梳理一下正则表达式的使用,主要关注的是正则的思想

边写边听五月天的派对动物。学会了正则省下的时间就可以去party了 ^_^

正则表达式概念

我们先来看看正则表达式的概念,毕竟正则的语法、使用都是围绕着它要解决的问题来的。

wikipedia定义:

正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),
又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法,
是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。

首先,正则表达式是一个字符串组成的模式,用来匹配一个字符串,一般用在检索,替换里,也经常用来校验一些字符模式,检验是否匹配一个给定的规则。

正则表达式的基本语法

正则表达式使用字符串来描述字符串,也就是说跟编程语言,正则表达式是有自己的关键字的,学会这些关键字是我们入门正则的第一步,然后在使用中领会正则表达式的思想,一步步进阶。

首先要明确一点,正则引擎在匹配时是一个字符一个字符的匹配的,跟我们平常印象中一串一串匹配的思维是不同的,这个需要我们时刻牢记。

匹配单个字符的元字符

我们首先来看一下匹配一个字符的关键字:

元字符 名称 含义
. 点号 匹配任意一个字符
[……] 字符组 匹配组内的单个字符
[^……] 排除性字符组 匹配单个未列出的字符
\meta 转义字符 特殊含义或转义元字符

英文点号可以匹配任意字符,但是不包括换行符,也就是说匹配到换行点号就匹配失败了,我们可以使用\n来匹配换行符,在java中也有MULTI_LINES来指定让点号匹配到换行符

如果我们想匹配一个文本形式的点号怎么弄呢,可以使用反斜线\来转义关键字,这样就可以匹配一个点号,而不是匹配任意字符的关键字点号了。

关于字符组需要说明一点,可以使用-来描述一个范围,比如我们想匹配数字,我们可以写一个全列[0123456789],也可以使用[0-9],字符也是一样[a-zA-z]匹配英文大小写的26个字母,如果我们想匹配横杠怎么办呢?只有一个办法,那就是把它写在紧跟左中括号后面,[-a-z]匹配横杠和a-z的所有字母,如果写在中间是会被当成关键字来解析的。

计数元字符

有了匹配单个字符的关键字,匹配多个就要用到计数元字符,常用的有下面这些:

元字符 名称 含义 区间表示
? 问号 匹配至多一次 {0,1} greedy的
* 星号 匹配任意多次,也可以不匹配 {0,}
+ 加号 匹配至少一次 {1,}
{min, max} 区间 min <=匹配次数 <= max grep默认不支持{元字符,可以使用-E选项
*?,+?,??,{min,max}? 忽略优先量词 匹配尽可能少的内容
*+, ++, ?+ {min,max}+ 占有优先量词 匹配内容后不会交还,类似固化分组

?*+这三个元字符是可以使用{}来模拟的,不过在一些正则流派里不支持{}元字符,我们只能使用这三个。

在为加?的量词上,前四个都是贪婪匹配的,也就是说他们会匹配尽可能多的字符,在匹配失败的时候才会停止,这有时候很有用,但有时候会让我们没有经过深思写出来的正则匹配到错误的内容。第四列在量词后面加了?则正相反,它会匹配尽可能少的内容,是先为人后为几的,这两种方式的区别我们后面再讲,这跟表达式引擎的递归与回溯有关。

最后一列是占有优先量词,这个概念是在贪婪的基础上加了铁公鸡属性(占有),也就是说经它匹配过的字符就是它的了,不会再吐出来。后面我们在讲回溯跟固化分组时是再来回顾这个占有优先量词。

简写

上面两者组合可以匹配大部分字符了,不过有些写起来很繁琐,因此正则为我们提前定义好了一些简写,使用时可以减少表达式长度。

元字符 名称 含义
\s [ \f\v\t\n\r] 匹配空格,制表符,回车、换行
\S 除\s之外的任何字符
\w [a-zA-Z0-9_] 匹配一个单词
\W [^a-zA-Z0-9] 匹配除\w外的任何字符
\d [0-9] 数字
\D [^0-9] 非数字

注:相同字母的小写跟大写在这是互补的,也就是互为补集,不过需要注意一点,在这里面没有包含Unicode字符,不同的正则引擎对这些有不同的实现,譬如\d有的正则引擎可以匹配Unicode中的数字,也就是说中文也是有可能匹配的,这个可以参考各自的语言工具书(不过一般这样用没啥问题)。

练习

我这里使用nodepad++来练习正则表达式,Linux下有些字符处理起来比较麻烦,Java写起来又太啰嗦,怎么简便怎么来。

找出一段文字中的数字

\d+[0-9]+

这里使用加号是因为数字至少出现一次才是合法的,如果使用*则可以匹配任意位置,因为*可以不匹配任何字符

日志里常根据关键字和id来定位,一般如何使用呢?

假设关键字为keyword, id为13235413,并且id在后面,我们可以使用keyword.*13235413来匹配含有这个模式的一行日志,这里加不加问号对我们没有影响

找出一行里含有至少10个单词的行,假设单词以空格分割


线


不存在唯一的答案,我是这样写的(\w++ *){10,},第一次写成了(\w+ *){10,},也就是没有使用占有优先量词,这个表达式是不符合要求的,大家可以试一下,然后想想,后面我们会在涉及到回溯与固化分组相关的时候就可以明白了。

猜你喜欢

转载自my.oschina.net/liufq/blog/1810099