读《精通正则表达式》
2019-03-06 本文已影响0人
JLUiceman
todo:提取要点,梳理结构图
第一章
1. ^脱字符
2. 正则表达式结构体(字符组)即=> [ ],只有在字符组内部且不是出现在头部,连字符(-)才是元字符,其他的元字符(脱字符除外)在字符组内部均为普通字符, 同时需要注意字符组只是匹配一个字符(和()多选结构区分开)
3. 排除型字符组表示的是"匹配一个未列出的字符"而非"不要匹配列出的字符",即是一种肯定断言,即使名字里包含了“排除”两个字,它仍然需要匹配一个字符
4. 一个字符组只能匹配目标文本中的单个字符,而每个多选结构自身都可能是完成的正则表达式,都可以匹配任意长度的文本
5. < 和 > 用于匹配单词的开头和结束位置(eg: <cat 匹配以cat开头的单词),<和>本身不是元字符,只有与反斜线结合时才是元字符(js不支持,可用\b元字符替代)
6. 可选项元素=> ? 与其他元字符不同,只作用于之前紧邻的元素or多选结构(即括号),表示此处容许出现或不出现这个字符
7.其他量词: + 表示之前紧邻的元素出现一次或多次; * 表示之前紧邻的元素出现任意多次获不出现;{ x, y} 表示之前紧邻的元素出现x-y之间的次数
8.反向引用: 允许匹配与表达式先前部分匹配的同样的文本(实测js实现的正则引擎不支持),用下划线+数字来表示(eg: ([a-z])(0-9)\1\2, \1表示[a-z]匹配的内容,\2表示[0-9]表示的内容)
9.转义符:\ 无需多言
10.常用的正则例子:
作用 | 正则 |
---|---|
匹配变量名 | [a-zA-Z_][a-zA-Z_0-9]* |
引号内的字符串 | "[^"]*" |
金额 | $[0-9]+(.[0-9][0-9])? |
11. 我觉得挺有道理的一句话:字节如何解释只是视角(或称作编码更合适些)的问题
第二章 (入门示例拓展)
1.一些Perl的tip:
命令 | 含义 |
---|---|
m/正则/ | 对该正则进行匹配 |
=~ | 连接正则表达式和待搜索的目标字符串 |
2. 用()来分组和捕获,用(?:)表示只分组不捕获·
3. 注意(x|y) 和[xy]*的区别
4. 字符组的子语言的规范不同于正则表达式主体,元字符的的定义在正则表达式中并不是统一的(eg: \b)
5. 一些元字符的简记法
元字符 | 含义 |
---|---|
\t | 制表符 |
\n | 换行符、 |
\r | 回车符 |
\s | 任何空白字符 |
\S | 任何非空白字符 |
\w | [a-zA-Z0-9] |
\W | 除\w以外的字符 |
\d | [0-9] |
\D | 非数字字符 |
6.Perl中使用2,$3....之类的变量来保存()分组匹配到的值,可以通过这种方法从字符串中提取信息
7.一种保留两位or三位小数(根据第三位是否非0)的正则表达式(Perl版本): s/(.\d\d[1-9]?)\d*/$1/
js版本: const reg = /(.\d\d[1-9]?)\d*/; const string = string.replace(reg, RegExp.$1)
8. "环视"结构不匹配任何字符,只匹配文本中的特定位置
顺序环视(从左往右): (?=正则)
逆序环视(从右往左): (?<=正则)
eg: 正则为: (?=Jeffrey)Jeff, 则Jeffrey可以匹配,Jeffrex不能匹配,尽管环视结构并不匹配任何字符
使用环视替换字符: Jeffs => Jeff's 则可以使用(perl语法)s/(?<=\bJeff)(?=s\b)/'/g(即找到这样一个位置: 紧接在Jeff之后,在s之前,将其替换为')
使用环视完成数字每三位插入一个逗号(16777272 => 16,777,272): s/(?<=\d) (?=(\d\d\d)+$)/,/g(即寻找这样的位置:左侧为数字,右侧为3的倍数个数字)
9. 其他环视
类型 | 正则表达式 | 匹配成功的条件 |
---|---|---|
肯定逆序环视 | (?<=.....) | 子表达式能够匹配左侧文本 |
否定逆序环视 | (?<!.....) | 子表达式不能够匹配左侧文本 |
肯定逆序环视 | (?<=.....) | 子表达式能够匹配右侧文本 |
肯定逆序环视 | (?<!.....) | 子表达式不能够匹配右侧文本 |
用环视表示\b(单词分界符)=> (?<!\w)(?=\w)|(?<=\w)(?!\w)
第三章(正则表示的特性和流派概览)
1.正则表达式的起源: 20世纪40年代的两位神经学家(Warren MCCulloch & Walter Pitts) => 数学家(Stephen Kleene)在代数中正式描述为"正则集合"
2.正则相关的工具:
- qed => ed(后发展为Unix中的ed编辑器)
- ed的"g/Regular Expression/p"最终成为独立的工具grep
- AT&T贝尔实验室的Alfred Aho写出了egrep
3.字符编码: 本质上是一种写明的共识,它规定了不同数值的字节应该如何解释,相同的字节用于不同的编码所代表的值可能不同
4.编码应该考虑的点
- 程序能否识别这种编码
- 程序如何决定采用哪种编码来处理这些数据
- 正则表达式对这种编码的支持程度如何
5.正则表达式编码支持程度应该考虑的点
- 是否能够支持多字节字符?eg: 点号(.)和[^x]之类的表达式是匹配单个字符还是单个字节?
- \w,\d,\s之类的元字符 ,是否额能够识别编码中的所有字符?eg:é亦是字符,此时能否匹配
- 程序是否会扩展对字符组的解释?eg: [a-z]能否匹配é
- 不区分大小写的匹配是否对所有字符有效?eg:é
6.Unicode相关
- 从基本的意义上说,Unicode是一组字符设定(或者是从数字和字符之间的逻辑映射的概念编码)(注意非编码)
而将这种映射的概念编码为数据的方式有很多: UCS-2(所有字符都占用两个), UCS-4(所有字符占用4个字节),UTF-16(大部分字符占用两个字节,有一些字符占用4个字节),UTF-8(用1-6个字节来编码字符) - 支持Unicode的程序中的正则表达式通常支持\u{unicode数字num}元序列,用来匹配一个具体的unicode字符;eg:\uC05B匹配的是编号为U+C05B的Unicode字符,而非具体的字节,因为具体的字节是由代表这个Unicode代码点的编码方式在内部决定的
- 一般人眼里的字符并不都会被Unicode或者支持Unicode的程序(正则引擎)看作一个字符,比如é看上去是一个字符,其实在Unicode中它可能有两个代码点构成(一个表示e,一个表示钝重音) =>带来问题:点号(.)是匹配单个代码点还是整个代码点组合
- 实践中,大部分程序将"字符"和"代码点"视为等价,及匹配单个代码点
- 理论上Unicode应该是代码点和字符之间的一一映射,实际上存在多种情况,例如à可以表示为U+0061加上U+0300,它也可以用单个代码点U+00E0表示(原因是为了保证Unicode和Latin-1之间转换的简易性)
- Unicode Version 3.1增加了U+FFFF之后的代码点(比如代表音乐谱号C的字符对应代码点U+1D121)
- Unicode中的行终止符(存在多种)=>影响文本行从文件读入的方式,影响正则的点号(.)及^,$和\Z的匹配
字符 | Unicode码 | 描述 |
---|---|---|
LF | U+000A | ASCII换行符 |
VT | U+000B | ASCII垂直制表符 |
FF | U+000C | ASCII进纸符 |
CR | U+000D | ASCII回车 |
CR/LF | U+000A U+000D | ASCII回车/换行 |
NEL | U+0085 | Unicode换行 |
LS | U+2028 | Unicode行分隔符 |
PS | U+2029 | Unicode段分隔符 |
7.正则模式和匹配模式
- 不区分大小写的匹配模式(i): 问题=>1.存在特殊的与Unicode相关的问题,即并非所有的ASCII字母和数字字符都存在大小写形式,某些字符在大写和小写之间没有明显的一对一映射
- 宽松排列和注释模式: 此模式忽略字符组外部的所有空白字符
- 点号通配模式(dot-match-all match mode,也叫单行模式):通常点号(.)无法匹配换行符,而大部分现代编程语言则提供了两种方法供正则表达式选择
- 增强的行锚点模式(Enhanced Line-anchor match mode,也叫"多行文本模式"):影响行锚点"^"和""一样,只是在此模式下它们的意义不会发生变化,永远不会匹配字串内部的换行符
- 文本文字模式: 此模式几乎不能识别任何正则表达式元字符(eg: [a-z]* 的正则在此模式下匹配的是字符串"[a-z]*")
- “多行模式”和"单行模式"的区别: 后者修改的是点号的匹配规则(换行符需要特殊处理=>不需要特殊处理),前者修改的是"^"和"$"的匹配规则(换行符不需要特殊处理=>需要特殊处理)
8.常见的元字符
- 字符缩略表示法
元字符 | 含义 | 解释 |
---|---|---|
\a | 警报 | 对应ASCII中的<BEL> |
\b | 退格 | 对应ASCII中的<BS>,八进制编码010,在许多流派中\b只有在字符组内才表示退格,否则代表单词边界 |
\e | Escape字符 | 通常对应ASCII中的<ESC>,八进制编码033 |
\f | 进纸符 | 对应ASCII中的<FF>,八进制编码014 |
\n | 换行符 | macos平台中对应ASCII的<CR>,其他平台对应<LF> |
\r | 回车 | 对应ASCII中的<CR>,MacOs中对应ASCII的<LF> |
\t | 水平制表符 | 对应ASCII中的<HT>,八进制编码011 |
\v | 垂直制表符 | 对应ASCII中的<VT>,八进制编码013 |
9.字符组及相关结构
- 字符组通常表示肯定断言,即它必须匹配一个字符,排除型字符组仍然需要匹配一个字符,只是它没有在字符组中列出而已(注意[a-Z]和[a-zA-Z]的区别)
- 点号能匹配除了换行符之外的任何字符(可以通过更改匹配模式切换)
- Unicode属性,字母表和区块(p121,暂不记录)
- .NET支持字符组减法(eg: [[a-z]-[aeiou]])
10.锚点及其他"零长度断言"(只匹配位置)
- 脱字符"^"匹配需要搜索的文本的起始位置,若使用了增强的行锚点匹配模式,还能匹配每个换行符之后的位置
第4章
1.正则引擎的分类
- DFA 确定有限自动机DFA
- NFA 不确定有限自动机