读《学习正则表达式》
准备
pcregrep
pcregrep是带有PCRE库的grep版本
Mac下安装pcregrep
brew install pcre
brew link pcre
第1章 什么是正则表达式
”正则表达式是描述一组字符串特征的模式,用来匹配特定的字符串。“ ------Ken Thompson
1.1 几个网址
这几个网址可以在线测试正则表达式
- https://www.regexpal.com/
- http://regexpal.com.s3-website-us-east-1.amazonaws.com/ 第1章用到
- http://tool.oschina.net/regex
- https://regexr.com/ 第2章用到
这是作者的github上关于本书的相关代码
https://github.com/michaeljamesfitzgerald/Introducing-Regular-Expressions
1.2 匹配北美的电话号码
北美的电话号码长这样:
707-827-7019
827.7079
(707)-827-7079
用字符串字面值来匹配:
用字符组来匹配数字:
[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]
使用字符组简写式:
# \d表示数字字符
\d\d\d-\d\d\d-\d\d\d\d
# 连字符 \D表示非数字字符
\d\d\d\D\d\d\d\D\d\d\d\d
匹配任意字符
# 点号(.)是一个通配符,可以匹配任意字符,但不匹配换行符
\d\d\d.\d\d\d.\d\d\d\d
捕获分组和向后引用
# 匹配区号707
(\d)\d\1
# 说明
(\d)匹配第一个数字7并将其捕获,括号表示捕获
\d匹配第二个数字0但没有捕获
\1对捕获的数字进行反向引用,表示第一个捕获,即数字7
使用量词
\d{3}-?\d{3}-?\d{4}
(\d{3,4}[.-]?)+
(\d{3}[.-]?){2}\d{4}
# 说明
{3}表示前面的匹配出现3次
+表示出现一个或多个
*表示0个或多个
?表示0个或1个
括选文字符
# 区号可以有也可以没有,可以带括号也可以不带括号
^(\(\d{3}\)|^\d{3}[.-]?)?\d{3}[.-]?\d{4}$
# 说明
|表示选择
^表示行首
$表示行尾
\(表示转义,即真正的左括号
1.3 编辑器
TextMate
Mac上的文本编辑器,采用与Ruby语言相同的正则表达式程序库
Notepad++
Windows上的编辑器,采用PCRE(Perl Compatible Regular Expression,Perl兼容正则表达式)库
Oxygen
XML编辑器,使用perl 5的正则表达式语法
第2章 简单的模式匹配
正则表达式的用途就是在文本中匹配和寻找模式。
匹配模式的简单方法:
- 字符串字面值
- 数字
- 字母
- 任意字符
在线正则表达式验证工具
2.1 匹配字符串字面值:
Ship
2.2 匹配数字
\d
[0-9]
[0123456789]
[01]
2.3 匹配非数字字符
\D
[^0-9]
[^\d]
2.4 匹配单词和非单词字符
# 匹配单词
\w
# 匹配非单词
\W
# 说明
\w与\D的区别:\D会匹配空格、标点符号等字符
\w:[_a-zA-Z0-9]
字符简写式
\a 报警符
[\b] 退格字符
\c x 控制字符
\d 数字字符
\D 非数字字符
\o xxx 字符的八进制值
\w 单词字符
\W 非单词字符
\0 空字符
\x xx 字符的十六进制值
\u xxx 字符的Unicode值
2.5 匹配空白符
# 匹配空白符
\s
# 匹配非空白符
\S
# 说明
\s与[\t\n\r]相同
匹配各种空白符的简写式
\f 换页符
\h 水平空白符
\H 非水平空白符
\n 换行符
\r 回车符
\s 空白符
\S 非空白符
\t 水平制表符
\v 垂直制表符
\V 非垂直制表符
2.6 匹配任意字符
\bA.{5}T\b
.*
# 说明
\b匹配单词的边界
.*与[^\n]相同
2.7 multiline与dotall模式
# 如果regexp里出现了^或者$, 那么by default只会匹配第一行. 设置了Multiline,会匹配所有行.
# 默认情况下, .不会匹配换行符, 设置了Dotall模式, .会匹配所有字符包括换行符
2.8 给文本加标签
# 给 The Rime of the Ancient Mariner 加标签
用sed为文本加标签
sed -n 's#^#<h1>#;s#$#</h1>#p;q' rime.txt
# 说明
三个命令,以;分隔
s#^#<h1># 表示行首加<h1>
s#$#</h1># 表示行尾加</h1>
q 表示结束sed程序,这样就只会处理一行
p 表示打印受影响的那一行
用sed的其他方式
# 使用e
sed -ne 's#^#<h1>#' -e 's#$#</h1>#p' -e 'q'
# 命令写入文件中
---h1.sed start---
#!/usr/bin/sed
s#^#<h1>#
s#$#</h1>#
q
---h1.sed end---
sed -fh1.sed rime.txt
用Perl为文本加标签
# 确认已经安装perl
perl -v
# 为第一行加标签
perl -ne 'if($. == 1){s#^#<h1>#;s#$#</h1>#m;print;}' rime.txt
# 说明
-n选项 输出全部输入内容
-e选项 允许在命令行中提交程序代码
if($. == 1) 检查是否在第一行,$.匹配当前行
m修饰符 多行修改符
写成perl脚本
---h1.pl start---
#!/usr/bin/perl -n
if ($. == 1) {
s#^#<h1>#;
s#$#</h1>#m;
print;
}
---h1.pl end---
# 执行
perl h1.pl prime.txt
第3章 边界
断言标记边界,但是并不耗用字符。也就是说,字符并不会返回到结果中。断言也被称做零宽断言(zero-width assertion)。零宽断言不匹配字符,而是匹配字符串的中的位置。^和$也叫做锚位符(anchor)。
边界有以下几种:
- 行或者字符串的起始与结束位置
- 单词边界
- 主题词的起始与结束位置
- 引用字符串字面值的边界
测试网址
测试文本
THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.
ARGUMENT.
How a Ship having passed the Line was driven by Storms to the cold
Country towards the South Pole; and how from thence she made her course
to the tropical Latitude of the Great Pacific Ocean; and of the strange
things that befell; and in what manner the Ancyent Marinere came back to
his own Country.
I.
1 It is an ancyent Marinere,
2 And he stoppeth one of three:
3 "By thy long grey beard and thy glittering eye
4 "Now wherefore stoppest me?
3.1 行的起始与结束
# 在multiline与dotall模式下,匹配How这一整段
^How.*Country\.$
# dotall模式下,匹配整个文本,因为.匹配包括换行符的所有字符
THE.*\?$
3.2 单词边界与非单词边界
# gloal模式下,匹配第一行的两个THE
\bTHE\b
\Be\B
# 说明
\b是个零宽度断言,表面上它会匹配空格或者是行起始,而实际上它匹配的是个零宽度的不存在的东西。
\b匹配单词边界
\B匹配非单词边界
\<匹配单词开头,vim和grep中可用
\>匹配单词结尾
grep -Eoc 'THE|The|the' rime.txt
grep -Eoc '\<THE|The|the\>' rime.txt
grep -Eoc '\bTHE|The|the\b' rime.txt
# 说明
-E选项表示使用扩展的正则表达式
-o选项表示只输出与模式匹配的那部分
-c选项表示只返回结果的数量
3.3 其他锚位符
# 匹配单词the出现在行首附近位置且之前有一个或多个空格的次数
pcregrep -c '\A\s*(THE|The|the)' rime.txt
# 说明
\A匹配主题词的起始
\Z匹配主题词的结尾
\s匹配空格
-c选项表示返回匹配次数
# 匹配主题词尾部的MARINERE或Marinere
pcregrep -n '(MARINERE|Marinere)(.)?\Z' rime.txt
# 说明
-n选项输出行号
3.4 使用元字符的字面值
# 15个元字符
.^$*+?|(){}[]\-
# 匹配$
\Q$\E
\$
# 说明
\Q\E之间的任意字符都会被解释为普通字符
第4章 选择、分组和向后引用
分组可以帮助执行某种操作:
- 在两种或更多可选模式中选择一个
- 创建子模式
- 捕获一个分组以便之后进行后向引用
- 对组合的模式使用某项操作,如量词
- 使用非捕获分组
- 原子分组
4.1 选择操作
(THE|The|the)
# 使用选项
(?i)the
正则表达式中的选项
参考http://pcre.org/pcre.txt 中的NAMED SUBPATTERNS(命名子模式)
?d Unix中的行
?i 不区分大小写
?J 允许重复的名字
?m 多行
?s 单行(dotall)
?u Unicode
?U 默认最短匹配
?x 忽略空格和注释
?-... 复原或关闭选项
使用grep统计the出现的次数
grep -Ec "(THE|The|the)" rime.txt
grep -Eo "(THE|The|the)" rime.txt | wc -l
# 说明
-E选项表示使用扩展的正则表达式(ERE),而不用基本的正则表达式(BRE)
-c选项表示返回匹配的行数(不是匹配的单词)
wc命令是单词计数命令
-l选项是对输入的行数进行统计
4.2 子模式
(the|The|THE)
(t|T)h(e|eir)
\b[tT]h[ceinry]*\b
4.3 捕获分组和向后引用
# 向后引用
\1或$1 引用第一个捕获的分组
sed只能接受\1这种形式
Perl则两种都接受
RegExr
sed
# 说明
-E选项调用ERE(扩展的正则表达式),括号可以直接当成字面值来使用
-n选项覆盖打印每一行的默认设置
p修改符表示要打印该行
命名分组
命名分组 引用分组
(?<one>It is) $+{one}或\kone或?P=one
4.3 非捕获分组
(?:THE|The|the)
(?i)(?:THE|The|the)
(?:(?i)the)
(?i:the) 推荐这样写
原子分组
如果使用的正则表达式引擎进行回溯操作,这种分组就可以将回溯操作关闭,但它只原子分组内的部分,而不是针对整个正则表达式。语法如下:
(?>the)
https://github.com/google/re2 非回溯引擎可彻底关闭回溯操作,而使用原子分组可以关闭正则表达式的部分回溯操作
第5章 字符组
字符组有时也被称为方括号表达式。
测试文本
! " # $ % & ' () * + , - . /
0 1 2 3 4 5 6 7 8 9
: ; < = > ? @
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
[ \ ] ^ _ `
a b c d e f g h i j k l m n o p q r s t u v w x y z
{ | } ~
字符组匹配
# 元音
[aeiou]
[a-z]
[a-f]
[0-9]
[3-6]
# 10~19的偶数
\b[1][24680]\b
# 0~99的偶数
\b[24680]\b|\b[1-9][24680]\b
# 十六进制数
[a-fA-F0-9]
5.1 字符组取反
# 不匹配元音字符
[^aeiou]
5.2 并集与差集
Reggy,Mac桌面应用程序
# 并集
[0-3[6-9]]
# 差集
[a-z&&[^m-r]]
5.3 POSIX字符组
POSIX(Portable Operating System Interface,可移植操作系统接口)是IEEE维护的一系列标准。其中包含了一个正则表达式标准(ISO/IEC/IEEE 9945:2009),该标准提供了一套命名的字符组,其形式为:
[[:xxxx:]]
xxxx是名字,如digit或word或alnum
# 对POSIX字符组取反
[[:^xxxx:]]
5.4 本章所学
- 如何使用方括号表达式创建字符组或字符集
- 如何在字符组中创建一个或多个范围
- 如何匹配0到99范围内的偶数
- 如何匹配十六进制数
- 如何在字符组中使用简写式
- 如何对一个字符组进行取反
- 如何得到字符组的并集和差集
- 什么是POSIX字符组