关于正则
第一次学习正则应该是在2012年的夏天,学的是30分钟入门教程。
其实30分钟根本学不完,正则表达式也就是Regular Expression要学会,必须在不断的匹配中了解其中种种。对我来说,正则就像把瑞士军刀,能解决各种棘手问题。
在线验证工具:
www.regexbuddy.com
www.debuggex.com/
哪用到了正则
- 正确性验证
- 数据匹配
- 数据整理
对我来说,这些应用的比较多。
例如验证日期的正确性,查找文章有多少段落,替换所有的制表符等等。
各个语言里的正则
正则表达式是个独立于语言,自成一套体系的东西。所以各个语言对它的实现程度各不相同,目前所接触的语言有JavaScript、Java、C++、PHP、Shell,个人感觉C++对正则的支持是最好的。JS多应用于前端,现在还有NodeJS想必正则的支持不会有多大差异,如果没记错JS的断言方面不支持后断言。还有Java,在1.6的JRE下是不支持断言,而在1.7中加入了零宽断言。除了编程语言,各个工具中其实也有自己的正则特性,例如Notepad的正则零宽断言不支持变长表达式。
正则的理解
个人对正则的理解是这样的,基础表达式是
元字符/组+[限定符]+[贪婪/懒惰]
也就是说正则对规则的描述类似自然语言,某些东西会在哪里出现、它不会在哪出现、出现多少次、是否一找到就不用再找等等。
正则描述对规则的限定十分严谨
[]
村里有个姑娘叫小芳,方括号代表者对单个位置上可能出现字符的描述。{}
花姑娘分外妖娆,花括号代表对字符、组的任意限定。()
大妈处事圆滑,圆括号内为一个组,越左、嵌套越深,组号越小。
元字符:
元字符 | 含义 |
---|---|
. | 代表任意字符 |
\b | 单词分隔 |
\d | 数字[0-9] |
\t | 制表符 |
\w | 英文字母 |
\s | 空格 |
限定符:
限定符 | 含义 |
---|---|
* | 任意多个 |
+ | 多于1个 |
? | 0或1个 |
{n} | n个 |
{n,} | 多余n个 |
{n,m} | n到m个 |
懒惰限定:
懒惰 | 含义 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
其他:
各个语言中还有一些可选项,可对匹配过程产生影响。
例如.
匹配换行符,^$
匹配多行等。
零宽断言是个好东西
语法 | 含义 |
---|---|
(?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 |
(?!exp) | 匹配后面跟的不是exp的位置 |
(?<!exp) | 匹配前面不是exp的位置 |
为便于理解,对 (?=exp)
也可以理解为,光标后边跟着exp表达式,匹配的是一个不占位的光标。例如:(?=\r\n|\n|\r)匹配所有所有行的末尾光标(ps.除了最后一行)
语法 | 含义 |
---|---|
(?=exp) | 光标后边是exp |
(?<=exp) | 光标前边是exp |
(?!exp) | 光标后边不是exp |
(?<!exp) | 光标前边不是exp |
还是这个表格好理解,上边的绕口令都把人绕晕了。
在实际使用中,零宽断言对整理数据非常好用。
一些武林绝学
还有好多东西没写到,像捕获、反向引用、平衡组等等。
高深的武学,往往复杂晦涩且威力强大,但使用的频率不高。
不管了先列出来再说吧:
语法 | 含义 |
---|---|
\a | 报警字符(打印它的效果是电脑嘀一声) |
\b | 通常是单词分界位置,但如果在字符类里使用代表退格 |
\t | 制表符,Tab |
\r | 回车 |
\v | 竖向制表符 |
\f | 换页符 |
\n | 换行符 |
\e | Escape |
\0nn | ASCII代码中八进制代码为nn的字符 |
\xnn | ASCII代码中十六进制代码为nn的字符 |
\unnnn | Unicode代码中十六进制代码为nnnn的字符 |
\cN | ASCII控制字符。比如\cC代表Ctrl+C |
\A | 字符串开头(类似^,但不受处理多行选项的影响) |
\Z | 字符串结尾或行尾(不受处理多行选项的影响) |
\z | 字符串结尾(类似$,但不受处理多行选项的影响) |
\G | 当前搜索的开头 |
\p{name} | Unicode中命名为name的字符类,例如\p{IsGreek} |
(?>exp) | 贪婪子表达式 |
(?<x>-<y>exp) | 平衡组 |
(?im-nsx:exp) | 在子表达式exp中改变处理选项 |
(?im-nsx) | 为表达式后面的部分改变处理选项 |
(?(exp)yes|no) | 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no |
(?(exp)yes) | 同上,只是使用空表达式作为no |
(?(name)yes|no) | 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no |
(?(name)yes) | 同上,只是使用空表达式作为no |