正则表达式
教程
语法
正则:匹配(核心,基础(其他的功能都是在匹配基础上的)), 提取。
一般我们要处理的 输入 都是字符串形式的。
正则表达式也是以字符串形式,也叫模式串,规则串。
(输入串中只要有部分 匹配 模式串的,那么就属于匹配,true,如果连部分都没匹配,就是不匹配,false)- 原生的正则表达式: 字符串形式 ‘/pattern/flags’.
模式串包裹在//中。
pattern的元字符: 普通字符,非打印字符(用转义表示),特殊字符,限定符,定位符。 语法
- 原生的正则表达式: 字符串形式 ‘/pattern/flags’.
元字符的完整列表以及它们在正则表达式上下文中的行为:语法2
flag,是标志/修饰符,正则表达式的标记用于指定额外的匹配策略。有g i m s。 语法3
注意事项
正则在不同环境下有不同的方言。 要注意区别。
- 有的正则表达式是 放在//里面的,如”/^(abc)(bcd)/g” g是修饰符/标记符 表示全局匹配。 放在//里的也是原生的正则表达式的语法。
- 有的直接开始 “^(abc)(bcd)”,修饰符在其他地方设置。
输入的字符串形式有单行,多行(含\n)。
正则表达式的单行模式 和 多行模式, /pattern/g, /pattern/gm。
多行模式 只是影响到 ^ $ 定位符的作用。如果没有^ $ 那么单行模式和多行模式没什么区别。- 对于正则表达式为单行模式,将输入的字符串(不管单行还是多行) 都以整体去处理。 ^ $ 定位整体的开头和结尾。
- 对于正则表达式为多行模式的,多行模式下会改变^和$的含义【^和$是匹配整个字符串的开头和结尾】,使它在任意一行的行首和行尾进行匹配,即每行每行处理。 如果没有^$那么会以所有行整体处理,不是以行为单位的一行一行处理。
- 注意,正则中的. 无法匹配\r \n。如果要做多行/跨行匹配,见下面讨论。多行/跨行匹配和 单行模式 多行模式没有关系,不同的概念。
<script> function myFunction(){ var str="runoobgoogle\ntaobao\nrunoobweibo"; var n1=str.match(/^runoob/g); // 匹配一个 var n2=str.match(/^runoob/gm); // 多行匹配 document.getElementById("demo1").innerHTML=n1; //runoob document.getElementById("demo2").innerHTML=n2; //runoob,runoob } </script>
<script>
function myFunction(){
var str="runoobgoogle\ntaobao\nrunoobweibo";
var n1=str.match(/runoob/g);
var n2=str.match(/runoob/gm);
document.getElementById("demo1").innerHTML=n1; //runoob,runoob
document.getElementById("demo2").innerHTML=n2; //runoob,runoob
}
</script>
跨行/多行匹配问题。
和正则表达式的单行模式 多行模式 没有必然关系。 参考
.不能匹配换行,\r和\n。(不匹配回车和换行)
解决跨行匹配问题:主要就是要解决\n或\r的匹配。- 使用s修饰符。 /pattern/s。
- 把 . 改为 (?:.|\n)
参考function myFunction(){ var str='123\n\rabcbcd'; var n1=str.match(/123.*/g); alert(n1); // ==> 123 }
正则/123.+/g 不能匹配 “123\nabc”。function myFunction(){ var str='123\nabcbcd'; var n1=str.match(/123.*/gs); alert(n1); //==> 123\nabcbcd }
正则/123.+/gs 可以匹配 “123\nabc”。
正则贪婪模式与非贪婪模式。链接
当 ? 字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
可以看到,在“整个表达式匹配成功”的前提下,非贪婪模式才真正的影响着子表达式的匹配行为,如果整个表达式匹配失败,非贪婪模式无法影响子表达式的匹配行为。
^ 表示开始。 $ 表示结束。 /^(abc)(bcd)$/ 表示 以abc开始 bcd结束。 /^(abc)|(bcd)$/ 表示以abc开始 或者 bcd结束, abcagugh, asugbcd, bcdsaa 不行, safabc 不行。 /^(abc)$|^(bcd)$/ 匹配 abc 或bcd。
()也用于捕获分组。例外,如果()中前面有如下会变成非捕获分组,变成先行 后行断言: ?:、?=、?<=、?!、?<!等。 ?:仅仅是非捕获。后面四种不仅非捕获,而且零宽(即不消耗字符),而且还有特定作用。
反向引用。 链接
反向引用。 向后处理视为正向,引用到前面的规则,所以叫反向引用。
(?:[1-9])([a-z]+)\1
123456runoobrunoob623runoob456 =>6runoobrunoob([1-9])([a-z]+)\1
123456runoob623runoob456 => 6runoob6
123456runoob123runoob456 => 无先行断言,后行断言。
?=、?<=、?!、?<! 的使用区别。链接
(?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion)
(?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)
(?<=pattern) 零宽正向后行断言(zero-width positive lookbehind assertion)
(?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)
我感觉这里不叫正向 负向,叫正 和 负更好, 正先行断言,负先行断言。正后行断言,负后行断言。记忆方法:这里正 负向是表示肯定 否定, 先行 后行是表示 位置在pattern的前 后。
还有其他的叫法, 正预测先行断言, 负预测先行断言。 正回顾后发断言, 负回顾后发断言。
正向肯定断言, 正向否定断言, 负向肯定断言, 负向否定断言。(从查找的方向看,这种叫法其实也合理)(最后的叫法最合理。)
正则表达式在编程语言中运用
在 Java 中,\\
表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如 Perl),一个反斜杠 \
就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \\
代表其他语言中的一个 \
,这也就是为什么表示一位数字的正则表达式是 \\d
,而表示一个普通的反斜杠是 \\
。
java 中的正则字符串(java字符串形式的正则表达式)是包裹在原生的正则表达式字符串上的(即实际上加了一个中间层做处理)。 所以要将java字符串形式的正则表达式 转为 原生的正则表达式字符串, 要\\d
。 java自己先对自己的字符串做处理的,而不是直接处理正则,其他的语法是直接处理正则,因此只要\d
.
Java中正则表达式。
- String类的方法中直接使用正则表达式模式串。
String 的str.replace(regstr, repstr) , str.find(regstr), str.match(regstr) - 专门的正则类。 Pattern类 (将模式串编译成pattern类)。 match类(由pattern类match方法得到match类实例)。
python中的正则表达式。 https://www.jianshu.com/p/5295c5988b7f
- 字符串类中的方法不支持正则规则。
- 专门的正则模块 re 模块。 1. 模块中的函数,re.match,re.search等。 2.专门正则相关的类。Pattern类 (re.compile(patstr) 将模式串编译成pattern类), match类(由pattern类match方法得到match类实例)。
匹配 查看一个字符串是否符合正则表达式的语法,一般返回true或者false
获取 正则表达式来提取字符串中符合要求的文本
替换 查找字符串中符合正则表达式的文本,并用相应的字符串替换
分割 使用正则表达式对字符串进行分割。
正则表达式引擎
https://blog.csdn.net/weixin_55267022/article/details/118082886
https://www.cnblogs.com/Bubgit/p/10240790.html
正则表达式/模式串。
根据正则表达式 构造 NFA, DFA。 (正则表达式引擎)
遍历字符串/待匹配字符串。 一个一个遍历, 跟随NFA DFA进行比较,
0.针对整个字符串而言,如果遍历到某个字符时不在NFA/ DFA的状态中,那么不匹配。 或者 如果遍历结束时不在终结状态,不匹配。 只有遍历结束时 在 NFA/DFA的 终结状态 才是匹配。
1.针对部分匹配而言,如果待匹配字符串部分 走到了终结状态,那么说明部分字符串符合正则表达式。(这个可用于提取)。如果整个过程都没走到终结状态,那么就是连部分都不匹配的。
手动流程: 1. 正则表达式,如果可以直观转DFA,可以直接转DFA。 如果不能,先转NFA(转NFA比较直观),再将NFA转DFA(手动)。 2.根据DFA处理待匹配字符串(手动) 。
正则表达式模式串->NFA->DFA—>匹配。
完整的正则表达式程序(两部分:表达式引擎+匹配),流程(代码形式):
根据 正则表达式字符串 生成 状态机(实际上是图结构)(有NFA,DFA) (节点是状态,线是输入的值)。 这个生成状态机部分的程序称为正则表达式引擎,用于生成状态机。(重点,难点)
然后利用状态机 去遍历待匹配字符串,看是否匹配。
https://blog.csdn.net/weixin_39969611/article/details/114613950
https://baijiahao.baidu.com/s?id=1736259056451963107&wfr=spider&for=pc
https://blog.csdn.net/weixin_43655282/article/details/108963761
https://blog.csdn.net/qq_40294512/article/details/89004777 好! move操作的为所有出现的输入值。
正则表达式 可以 直观的 转为 NFA。 NFA状态转换图和转换表 都是 直观的看出正则表达式的 含义。
但是对于程序而言,这个不好处理,因为对输入是不确定的。 对计算机而言更合适处理的的是DFA,因此将NFA转成DFA。 转换DFA时,可能会出现多个结束状态。
NFA 转 DFA, 要引入闭包的概念和操作。
对任何非确定的有穷自动机N ,存在定义同一语言的确定的有穷自动机D。对任何确定的有穷自动机D ,存在定义同一语言的非确定的有穷自动机N
NFA/DFA 都有状态转换图,状态转换表。 起始状态 终结状态。
NFA 有 带有和不带有“ε-边”的NFA。 两者等价。 一般用带有”ε-边”的NFA。 一般 带有”ε-边” 可以变为只有一个终结状态,而不带有”ε-边”可能会有多个终结状态。
NFA的不确定性:多值映射(输入一个值有多个状态转换),带空转移。
NFA/DFA 可以用在正则表达式。 也可以用在编译原理 的词法分析阶段(将源程序/字符串形式 生成token表)。