快速掌握正则表达式

关键词 正则 状态机 环视匹配 等价转换 限定符 内联模式java

一.DFA引擎 or NFA引擎

不一样类型的正则引擎对一样的正则表达式执行的结果是不一样的。搞清楚引擎是必要的。git

概念

DFA(Deterministic Finite Automaton)为肯定性有限自动机,NFA(Non-deterministic Finite Automaton)为非肯定性有限自动机。正则表达式

  • DFA 引擎在线性时状态下执行,由于它们不要求回溯(并所以它们永远不测试相同的字符两次)
  • NFA包含回溯算法也叫试探法,从一条路往前走,能进则进,不能进则退回来,换一条路再试。回溯算法说白了就是穷举法。所以,在最坏状况下,它的执行速度可能很是慢。

能够用以下的正则表达式测试当前编程语言采用的引擎是否 NFA:nfa|nfa not算法

js:"nfa,nfa not".match(/nfa|nfa not/)  结果 ["nfa", index: 0, input: "nfa,nfa not", groups: undefined]
js:/nfa|nfa not/.test('nfa')  结果 true 
复制代码

用上面的正则表达式来测试字符串 nfa not,NFA 引擎在检测知足 nfa 就返回匹配成功的结果了,而 DFA 则会尝试继续查找,也就是说会获得“最长的匹配结果”。编程

知识点:自动机、自动机bash

如/\d\w+/这个正则生成的状态机图:网络

关于正则引擎如何工做这里有一个不错的说明,先说明了DFA工做的方法,而后又引出了“回溯”less

正则引擎语言分类

DFA类型 语言
DFA awk (大多数版本)、egrep(大多数版本)、flex、lex、MySQL、Procmail
传统型NFA GNU Emacs、Java、grep(大多数版本)、less、more、.NET语言、PCRE library、Perl、PHP(全部三套正则库)、Python、Ruby、sed(大多数版本)、vi ,JavaScript
POSIX NFA mawk、Mortice Kern Systems’ utilities、GNU Emacs (明确指定时使用)
DFA/NFA 混合 GNU awk、GNU grep/egrep、Tcl

不一样的语言对于正则表达式符号的支持状况也是不一样的。 编程语言

二.正则表达式

经常使用符号

简洁版post

  • ?表示匹配0个或1个
  • +表示匹配1-无穷
  • *表示匹配0-无穷
  • .表示除\n以外的任意字符
  • ^为匹配输入字符串的开始位置
  • $匹配结束位置
  • \d就是[0-9]。表示是一位数字。记忆方式:其英文是digit(数字)。
  • \D就是[^0-9]。表示除数字外的任意字符。
  • \w就是[0-9a-zA-Z_]。表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。
  • \W是[^0-9a-zA-Z_]。非单词字符。
  • \s是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。
  • \S是[^ \t\v\n\r\f]。 非空白符。.就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想一想省略号...中的每一个点,均可以理解成占位符,表示任何相似的东西。

wsb 和 WSB 是相反的

等价 \w = [A-Za-z0-9_], 展开看好理解

分解: 没法一步就完成的需求能够分解,如获取网页中的图片地址, 先获取img标签,而后再从标签中获取src值

特殊字符

参考版

特别字符 描述
$ 匹配输入字符串的结尾位置。若是设置了 RegExp 对象的 Multiline 属性,则$ 也匹配 '\\n' 或 '\\r'。要匹配 $ 字符自己,请使用 \\$
( ) 标记一个子表达式的开始和结束位置。子表达式能够获取供之后使用。要匹配这些字符,请使用 \( 和 \)。
* 匹配前面的子表达式零次或屡次。要匹配 * 字符,请使用 \*。
+ 匹配前面的子表达式一次或屡次。要匹配 + 字符,请使用 \+。
. 匹配除换行符 \n 以外的任何单字符。要匹配 . ,请使用 \. 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符自己,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。

限定符

限定符用来指定正则表达式的一个给定组件必需要出现多少次才能知足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。

正则表达式组成

正则表达式能够包含子表达式、小括号(子表达式部分)、中括号(主干部分)、大括号(限定部分)。这些括号组合是比较灵活的,能够相互包含(但大括号能不能包含其余括号)。

源字符串:<div>a test</div>
正则表达式:(?<=<div>)[^<]+(?=</div>)
复制代码

环视匹配

Lookaround, 也叫零宽断言

  • 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的。环视匹配的最终结果就是一个位置(肯定位置的过程)。
  • 环视的做用至关于对所在位置加了一个附加条件,只有知足这个条件,环视子表达式才能匹配成功。

示例1:

金额匹配: `(^0\.[0-9]{1,2}$)|(^[1-9]\d+\.[0-9]{1,2}$)|(^[1-9]\d+$)`
金额匹配(环视匹配): `(?!^0\d+|\D*0$)^[0-9]{1,7}(\.[0-9]{1,2})?$`
复制代码

这里常规金额匹配由三个子表达式组成,要排除整数部分为0开头的状况,整个过程比较冗长。换成环视匹配后就简单多了,环视匹配表达式的含义为 匹配除0开头的整数部分和非数字,整数部分长度1-7位。

优化金额 前:/^\d+(\.\d{1,2})?$/ 问题:12.校验经过; 优化后:/^\d+[.]\d{1,2}$|^\d+$/ 有“.” 小数部分必填。

示例2:

源字符串:aa<p>one</p>bb<div>two</div>cc
正则表达式:<(?!/?p\b)[^>]+>
复制代码

这个正则的意义就是匹配除了<p···>或

以外的全部标签 按图所示,这个正则中<就匹配它自己,(?!/?p\b)是一个顺序否认表达式,子表达式是</?p\b,意思是这个表达式的右边不能是字符【/p】或者【p】,问号是表明匹配一次或者不匹配,你们应该还记得。而后[^>]+中的[^···]是排除型字符组,表示的是除【>】之外的字符均可以匹配,匹配的数量是最少一次,最多不限制。最后一个表达式>的意义是匹配它自己。 上面整个表达式的含义就是:匹配【<(<右边不能是p或/p)(除>的字符N个)>】这样一个文本。由此例子,咱们也能够看出,表达式一般能够拆分红一个个的子表达式,最后把它们连起来造成一个完整的表达式。

正序否认环视匹配

(?=Expression)
顺序确定环视,表示所在位置右侧可以匹配Expression
(?!Expression)
顺序否认环视,表示所在位置右侧不能匹配Expression
复制代码

逆序环视匹配

(?<=Expression)
逆序确定环视,表示所在位置左侧可以匹配Expression
(?<!Expression)
逆序否认环视,表示所在位置左侧不能匹配Expression
复制代码

开头都是 "?"

都包含 “=”或“!”; 确定否认。(都包含确定”=”或 否认“!”)

逆序包含"<"

全局匹配模式和内联匹配模式

内联匹配模式特征:正则前面的(?i)(?s)(?m)(?is)(?im)

称为内联匹配模式,一般用内联匹配模式代替使用枚举值RegexOptions指定的全局匹配模式,写起来更简洁。

  • (?i)表示所在位置右侧的表达式开启忽略大小写模式
  • (?s)表示所在位置右侧的表达式开启单行模式。
  • 更改句点字符(.)的含义,以使它与每一个字符(而不是除\n以外的全部字符)匹配。
  • 注意:(?s)一般在匹配有换行的文本时使用
  • (?m)表示所在位置右侧的表示式开启指定多行模式。
  • 更改^和$的含义,以使它们分别与任何行的开头和结尾匹配,
  • 而不仅是与整个字符串的开头和结尾匹配。
  • 注意:(?m)只有在正则表达式中涉及到多行的“^”和“$”的匹配时,才使用Multiline模式。
  • 上面的匹配模式能够组合使用,好比(?is),(?im)。
  • 另外,还能够用(?i:exp)或者(?i)exp(?-i)来指定匹配的有效范围。

经常使用正则表达式练习

- 金额校验包含最小最大值 ` ^0(?!\d+$)\.[0-9]?[1-9]{1}$|^2[0]{5}$|(?!^[0,2-9]\d+|\D*0$)^[0-9]{1,6}(\.[0-9]{1,2})?$`
- 手机号` ^1[3|5|8|6|9]\d{9}$ `  
- 身份证` err:\d{15}$|\d{17}[\d{1}|X|x]$; right:^\d{17}[\d|X|x]{1}$|^\d{15}$`
- 通常信息填写:` ^([^\x00-\xff]|[A-Za-z0-9_-]|[()()]|[\\s])*$ `; //assic0-255除数字、大小写字母、之外的字符、这个正则杀马特字符是能够输入的
- 中文\英文\数字\下划线 `^([\u4e00-\u9fa5]|[A-Za-z0-9_-])*$`  
- 各类电话号码匹配,容许格式: 1398888888八、010-8888888八、010-88888888-88(转接号)、400888888:`(^1[3|4|5|8|6|9]\d{9}$)|(^\d{3,4}-\d{7,8}(-\d{1,3})?$)|(^400\d{6}$)`
- 日期  `^[1,2]+[0-9]{3}-(0[1-9]|1[0,1,2])-(0[1-9]|([1,2][0-9]{1})|3[0,1]{1})$`
- 大于0的数 `/^[0-9]\d*(\.\d+)$/` => `/^[0-9]\d*(\.\d+)$/.test('1.0')`

1.验证用户名和密码:("^[a-zA-Z]\w{5,15}$")正确格式:"[A-Z][a-z]_[0-9]"组成,而且第一个字必须为字母6~16位;
2.验证电话号码:("^(\d{3,4}-)\d{7,8}$")正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;
3.验证身份证号(15位或18位数字):("^\d{15}|\d{18}$");
4.验证Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
5.只能输入由数字和26个英文字母组成的字符串:("^[A-Za-z0-9]+$") ;
6.整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$
7.只能输入数字:"^[0-9]*$"。
8.只能输入n位的数字:"^\d{n}$"。
9.只能输入至少n位的数字:"^\d{n,}$"。
10.只能输入m~n位的数字:。"^\d{m,n}$"
11.只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。
12.只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。 => "^[0-9]+(\.[0-9]{2})?$"
13.只能输入有1~3位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"。=> "^[0-9]+(\.[0-9]{1,3})?$"。
14.只能输入非零的正整数:"^\+?[1-9][0-9]*$"。
15.只能输入非零的负整数:"^\-[1-9][]0-9"*$。
16.只能输入长度为3的字符:"^.{3}$"。
17.只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。
18.只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。
19.只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。
20.验证是否含有^%&',;=?$\"等字符:"[^%&',;=?$\x22]+"。 21.只能输入汉字:"^[\u4e00-\u9fa5]{0,}$" 22.验证URL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。 23.验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"1"~"12"。 24.验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"和"1"~"31"。 25.获取日期正则表达式:\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日? 评注:可用来匹配大多数年月日信息。 26.匹配双字节字符(包括汉字在内):[^\x00-\xff] 评注:能够用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1) 27.匹配空白行的正则表达式:\n\s*\r 评注:能够用来删除空白行 28.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</>|<.*? /> 网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力 var regexp =/^([\u4e00-\u9fa5]|[A-Za-z0-9_-])*$/g; if(!regexp.test(content.trim())){ // 不符合正则 } - .*匹配除 \n 之外的任何字符。 - /[\u4E00-\u9FA5]/ 汉字 - /[\uFF00-\uFFFF]/ 全角符号 - /[\u0000-\u00FF]/ 半角符号 - Java不支持 ?、+、|、(),那应该怎么实现呢? 首先要知道这件事,以后在java平台写正则时要看java的文档 复制代码

基础手册

记住经常使用符号是必要的,长时间不用忘记也很正常,查询手册在这里

See Also

相关文章
相关标签/搜索