正则表达式工作中一直在使用,但是没有系统的总结过,今天就从小白的角度梳理一下正则表达式的使用,主要关注的是正则的思想
边写边听五月天的派对动物。学会了正则省下的时间就可以去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,}
,也就是没有使用占有优先量词,这个表达式是不符合要求的,大家可以试一下,然后想想,后面我们会在涉及到回溯与固化分组相关的时候就可以明白了。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有