[TOC]

0x00 前言介绍

正则表达式(Regular Expression)描述字符串结构模式的形式化表达方法,正则(Regex)表达式处理的对象的字符串或者抽象地说是一个对象序列(计算机体系的本质数据结构)
正则表达式是一种文本模式包括普通字符(例如a 到 z 之间的字母)和特殊字符(称为”元字符”),用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”;


正则表达式发展历史
正则表达式的”祖先”可以一直上溯至对人类神经系统如何工作的早期研究,Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为”神经网事件的表示法”的论文,引入了正则表达式的概念。
正则表达式就是用来描述他称为”正则集的代数”的表达式,因此采用”正则表达式”这个术语,随后发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix 的主要发明人。


为什么使用正则表达式?
答:典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于对静态文本执行简单搜索和替换任务可能已经足够了,但它缺乏灵活性若采用这种方法搜索动态文本,即使不是不可能至少也会变得很困难。

正则表达式特点:

  1. 灵活性、逻辑性和功能性非常的强;
  2. 可以迅速地用极简单的方式达到字符串的复杂控制;
  3. 对于刚接触的人来说比较晦涩难懂,如果想学得大成任然需要系统的学习;
  4. 构造正则表达式的方法和创建数学表达式的方法一样,也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。



正则表达式学习难点

  • regex的使用
  • regex的特性(feature)
  • regex的工作原理:正则表达式引擎(regular expression engine)


正则表达式应用
描述:正则表达式的目标从宏观的角度看,一个正则表达式要么能够匹配给定的文本,要么就不能匹配;

  • 正则表达式在生物信息学和人类基因图谱的研究中发挥关键的作用;
  • 正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
  • 正则表达式在(文本编辑EditPlus、文字处理软件Microsoft Word、系统开发工具Visual Studio、数据库引擎、搜索工具)
  • 正则表达式是一串文本(a chunk of text)的特征,可以使用来验证用户输入的数据也可以用它来检索大量的文本,也可以进行控制数据(查找匹配文本/删除|替换|提取文本)
  • 正则表达式正在作为编程语言的一部分:Java/JScript/VisualBasic/VBscript/JavaScript/ECMAScript/C/C++/C/elispse/Perl/Python等等开发环境
  • 正则表达式在 *nix(Linux, Unix等)、HP 等操作系统中


WeiyiGeek.正则表达式应用情况

WeiyiGeek.正则表达式应用情况

应用场景

  • 开发输入校验: 例如可以测试输入字符串以查看字符串内是否出现电话号码模式或信用卡号码模式称为数据验证。
  • 安全拦截: 比如XSS,SQL注入以及playload-POC测试验证字符串的匹配拦截,常常出现在云waf和传统web的网站防火墙WAF中;
  • 例如,您可能需要搜索整个网站,删除过时的材料以及替换某些 HTML 格式标记。

验证正则表达式工具:

  • egrep #在Linux和windows平台中都有,值得注意的时候当egrep在正则匹配时候,会把换行符替换掉拼接下一行的字符;
  • Perl #提供的元字符和操纵能力远远多于egrep,且Perl对正则表达式的支持完整且易于使用;所以推荐在使用正则的时候采用此种方法;

0x01 正则表达式入门

完整的正则表达式由两种字符构成,特殊字符(special characters)也叫元字符(meta characters)其他为文字或者普通文本字符(normal text chracters),当然有的开发语言存在正则表达式的扩展;

正则与文件名模式之间的对比:

  • 附加的特殊字符构成的元字符通配符表达式,但是表达能力还是有限的;
  • 强大的模式语言和模式本身被称为正则表达式(通用的模式语言),

正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

  • 正则表达式是由普通字符(例如字符 a 到 z ,0-9)以及特殊字符(称为”元字符”)组成的文字模式。
  • 模式描述在搜索文本时要匹配的一个或多个字符串,正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

正则表达式的分类
描述:突出了正在表达式特性差异,支持正则表达式的语言都提供了自己的”改进”,从而成就了数目众多的正则表达式”流派 flavor”;(即正则Regex的流派Flavor不同,关于转义的规定也不相同)

  • 基本的正则表达式(Basic Regular Expression 又叫 Basic RegEx 简称 BREs)
  • 扩展的正则表达式(Extended Regular Expression 又叫E xtended RegEx 简称 EREs)
  • Perl的正则表达式(Perl Regular Expression 又叫 Perl RegEx 简称 PREs)

WeiyiGeek.正则基本扩展一览表

正则表达式的详解
正则表达式基础组成部分:普通字符和元字符类,以及语言扩展POSIX字符类:

  • 普通字符:
    • 包括没有显式指定为元字符的所有可打印和不可打印字符,包括所有的大小写数字(a-zA-Z0-0)以及所有的标点符号([email protected]#$%^&*()_+-={}|;:’”<>,./);
    • 非打印字符: ascii 前32位非打印字符;
  • 特殊字符(元字符):
    • 基础元字符(转义)
    • 定位符(匹配开始或者结尾)
    • 字符组(Character Classes)
    • 单词分界符
    • 预定义字符集
    • 数量限定符:用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配;
    • 特殊元字符
    • 分组符号
    • 非捕获型括号
WeiyiGeek.正则表达式分类表

WeiyiGeek.正则表达式分类表


正则表达式运算符优先级
描述:正则表达式相同优先级的从左到右进行计算,不同优先级先高后低,并且遵循优先级顺序,这和算法表达式非常类似;

WeiyiGeek.regular优先级

WeiyiGeek.regular优先级


基础元字符

描述:常用的一些元字符集基础入门学习regular必备;

1
2
3
4
5
6
7
8
9
.   #点号(point)用来匹配任意一个字符的字符集,	匹配除 "\n" 之外的任何单个字符。
\ #将下一个字符标记为一个特殊字符从而转变成元字符、或一个原义字符、或一个向后引用、或一个八进制转义符,注意在字符组里无效;

# \ 加上元字符:表示匹配元字符所使用的普通字符(例如\* 匹配普通的星号)
# \ 加上非元字符: 组成一种由具体实现方法规定其他医院的元字符序列 (例如:\< 表示单词的起始边界)
# \ 加上任意其他字符,默认情况就是匹配此字符(例如;反斜杠被忽略)

x|y #子表达式(Subexpression)是指整个正则表达式中的一部分,通常是括号内的表示或者由"|"分割的多选分支
#是一个简洁的元字符它表达的意思是或者逻辑,操作符号匹配 x 或 y注意不要再[]中使用,此时他只是一个'|'字符而已;常常和分组符号连用()

基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#实例1:转义符号的妙用,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("
echo "123\nabcdefg" | egrep -o '\\n'
\n


#实例2.例如'z|food' 能匹配 "z" 或 "food" 或者 '(z|f)ood' 则匹配 "zood"
echo "zreo food" | egrep -o 'z|food' #能够同时匹配其中任意一个正则表达式,子表达式称为"多选分支(alternative)"
z
food
echo "zreo food zood" | egrep -o '(z|f)ood' #逻辑或元字符常用模式;
food
zood

#实例3.例如匹配日期时间
echo "03/19/2019 03-19-2019 03.19.2019" | egrep -o "03[-./]19[-./]2019"
03/19/2019
03-19-2019
03.19.2019


#示例4.要匹配包括 '\n' 在内的任何字符,请使用像"(.|\n)"的模式。
echo -e "03/19/2019\n03-19-2019\n03.19.2019" | egrep -o "(.|\n)" --color


定位符

描述:如果设置了 RegExp 对象的 Multiline 属性,^|$ 也匹配 ‘\n’ 或 ‘\r’ 之前后的位置。

1
2
3
4
5
6
^	匹配输入字符串的开始位置。
$ 匹配输入字符串的结束位置。

#补充说明
^$ 代表空白行
^单词$ 代表匹配一个单词

基础案例:

1
2
3
4
5
6
7
8
9
10
11
#实例1:匹配开头和结尾
echo "start 123456789 end" | egrep -o '^start'
start
echo "start 123456789 end" | egrep -o 'end$'
end

#实例2: 联用则匹配空白行
echo -e "start \n\n123\n\n end" > regular_demo1.txt
egrep -n '^$' regular_demo1.txt
2:
4:


字符组

描述:字符组(字符集-character set)为了避免混淆更改叫法,可以看作是一个字符集范围内的字符;

1
2
3
4
5
" - "   字符组元字符"-"表示一个范围(character-class metacharacter)
[xyz] 字符集合匹配所包含的任意一个字符。例如'[abc]' 可以匹配 "plain" 中的 'a'
[^xyz] 负值字符集合匹配未包含的任意字符。例如'[^abc]' 可以匹配 "plain" 中的'p''l''i''n'
[a-z] 字符范围匹配指定范围内的任意字符。例如'[a-z]' 可以匹配 'a''z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符(排除型字符组同样是一种肯定断言(positive assertion))。例如'[^a-z]' 可以匹配任何不在 'a''z' 范围内的任意字符。

基础案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#实例1:比如在匹配英语单词的时候,有很多英语都是相似的我们可以采用正则进行提取
echo "I thinks separete and separate" | egrep -o "separ[ea]te"
separete:分离
separate:独立


#实例2.匹配数字大小写下划线已经惊叹号点号和问号
echo -e "123456789abcABC_\!.?"| egrep "[0-9a-zA-z_\!\.?]"
123456789abcABC_\!.?

#实例3.HTML中的H标签匹配
echo "<h1>h1</h1><h6>H6</h6>" | egrep -o "<h[1-6]>"
echo "<h1>h1</h1><h6>H6</h6>" | egrep -o "<h[123456]>"
<h1>
<h6>

#实例4.排除字符后所紧更的字符
echo "123456abcdefABCDEFG" | egrep -o "abc[^ABC]"
abcd


#示例5.表示时刻的文字例如9:17am或者12:30 pm (优化值得学习)
(1[012]|[1-9]):[0-5][0-9]*(am|pm)
#24小时 09:59
([01]?[0-9]|2[0-3]):[0-5][0-9]

注意事项

  • 所有特殊字符在字符集中都失去原有的特殊含义,在字符集中如果要使用] - ^ 等符号需要在前面加上的一个转义字符;
  • 一个字符组即使排除型字符组,也需要匹配一个字符;


单词分界符

描述:就是单词或者字符串的边界匹配(单词开头和结尾),并且不消耗匹配字符串中的字符;

1
2
3
4
5
\<  #匹配开始位置,<本身不是元字符当与斜线联合使用时候才是;
\> #匹配结尾位置, 同上

\b #匹配 单词边界 也就是指单词和空格间的位置。'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B #匹配 非单词边界 也就是指非单词和空格间的位置。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。

基础示例:

1
2
3
4
#示例1.匹配单词前后
echo "abc Love Study Compumter" | egrep -io '\<(abc|love)\>' --color
abc
Love

注意事项:

  • \< 与 \> 在某些egrep版本可能不支持;


预定义字符集

描述:可以单独使用也能在字符集中使用,匹配数字或者非数字,空白符号或者非空白符号,单词词组或者非单词词组;

1
2
3
4
5
6
\d	匹配一个数字字符    #等价于 [0-9]。
\D 匹配一个非数字字符 #等价于 [^0-9]。
\s 匹配任何空白字符包括空格、制表符、换页符 #等价于 [<空格> \f\n\r\t\v]。
\S 匹配任何非空白字符 #等价于 [^ \f\n\r\t\v]。
\w 匹配包括下划线的任何单词字符 #等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符 #等价于 '[^A-Za-z0-9_]'。

注意事项:

  • 对于\w元字符需要注意带有_下划线;


数量限定符

描述:匹配前面正则或者字符0次或者多次,是正则表达式中最常用的元字符了;

1
2
3
4
5
6
7
8
9
?	匹配前面的子表达式 零次或一次。#例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
* 匹配前面的子表达式 零次或多次。#例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式 一次或多次(至少一次)。#例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

#区间量词(interval quantifier): 规定重复次数的范围注意该方法不一定通用
{min,max} #至少需要min次,至多容许max次
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+''o{0,}' 则等价于 'o*'
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

贪婪模式和非贪婪模式

1
2
3
4
5
?	当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时匹配模式是非贪婪的。
非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
#例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

.* 的警告通常用来表示 "一组任何字符",点号可以匹配任何字符,而星号可以为任意数目但是并非必须.

基础示例:

1
2
3
4
5
6
7
#示例1.匹配前面字符0次或者1次,所以前面的单词或者分组匹配时候有则匹配无则不匹配;
echo "abdcd" | egrep -o "abc?"
ab

#示例2.使用区间量词匹配美国股票代码
echo "000333" | egrep -o '[a-zA-Z0-9]{1,6}'
000333

注意事项:

  • 每个量词都规定了匹配成功至少需要次数的下限,以及尝试匹配的次数上线,对某些量词来说下线是0而某些量词的上限是无穷大;
  • 由星号和问号限定的对象在 “匹配成功” 时可能并没有匹配任何字符,即使什么字符都不能匹配到,它任然会报告 “匹配成功”


特殊元字符

描述:特殊元字符描述在Ascii中不可见字符,注意在其他开发或者脚本语言中不一定是通用;元字符具有特殊意义的字符但是在正则表示中并不是统一的(在其他的一些高级语言中),在正则表达式的内部字符组有自己的子语言,其中的元字符是不同的;

1
2
3
4
5
6
\cx	匹配由X指明的控制字符;#例如:\cM匹配一个Control+M或者回车符号,x的值必须是A-Za-z范围内,否则将c视为一个原意单字符;
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

实际案例:

1
2
3
4
$ perl -E 'if("a\nb\tc" =~ m/\cI|\n/){print "匹配成功"}'
匹配成功
$ perl -E 'if("a\nbc" =~ m/\cI|\n/){print "匹配成功"}'
匹配成功


分组符号

描述:我们已经知道了()的两种用途,现在来介绍第三种:

  • 限制多选项的范围
  • 将若干个字符组合成为一个单元,受?与*之类的量词作用
  • 分组和反向引用

基础符号:

1
2
3
()  #限制多选项范围,组成单元字符串,分组重复利用,注意要匹配圆括号字符,请使用 '\(' 或 '\)'。
(pattern) #匹配 pattern 并获取这一匹配。获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合在JScript 中则使用 $0…$9 属性。
\1 - \n #表示反向引用第几个()括号中匹配的字符串文本;即括号能够记忆其中的子表达式匹配的文本;

基础示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#示例1.\1代表匹配的前面的一个分组[a-z],\2代表了后面的一个分组\2
echo "aa11 b2c3 d44" | egrep -o '([a-z])\1([0-9])\2'
aa11

#示例2.如果不采用反向引用则两个the会进行换行输出
echo "the the" | egrep -o '([A-Za-z]+) \1'
the the
#该Eegrep版本-i参数无Bug,还是可以正常识别反向引用中的大写
echo "the The" | egrep -io '([a-z]+) \1'
the The


#示例3.匹配美元金额的办法
'\$[0-9]+(\.[0-9][0.9])?'

注意事项:

  • 尽管反向引用非常实用,但是它任然有它的局限性;因为egrep把每行文件都当做一个独立部分来看待(当匹配行尾与行首的字符时候容易出现BUG);


非捕获组

描述:它只用于分组,而不会影响文本的捕获和变量的保存;前面我们使用()来表示分组和捕获,而现在使用(?:)表示只分组不捕获,而且这里?和表示匹配数量限定符无任何联系,简单的说以 (?) 开头的组是非捕获组,它不捕获文本也不针对组合计进行计数。

如果小括号中以?号开头,那么这个分组就不会捕获文本
好处:避免了不必要的操作,提高匹配效率
缺点: 是增加了整个表达式的阅读难度

1
2
(?:pattern)	#匹配 pattern 但不获取匹配结果这是一个非获取匹配不进行存储供以后使用
(?:abc){2} #匹配 pattern 两次

基础示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#例如:使用或字符“(|)”来组合一个模式的各个部分是很有用
industr(?:y|ies) #比“industry|industries”更简略的表达式


#示例1.perl命令行匹配正则
$ perl -E 'if("a\nb\tc" =~ m/\cI|\n/){print "匹配成功"}'
匹配成功
$ perl -E 'if("a\nbc" =~ m/\cI|\n/){print "匹配成功"}'
匹配成功

#比如还是匹配我们输入的华摄氏度,即使[CF]两端的括号是第三组,由于采用了(?:)将不会捕获第二组,从而将后面匹配到的组往前挪;
'if("57F" =~ m/^([-+]?[0-9]+(?:\.[0-9]*)?)([CF]$/){
print "$1 $2
}'
#执行结果
57 F


环视功能

描述:正则表达式新特性环视(lookaround),环视结构不匹配任何字符只匹配文本中的特定位置,与单词分节符\b和^以及$相似但是又比他们更加通用;

  • 顺序环视(lookahead):作为表达式的而一部分,顺序环视顺序(从左至右)查看文本,尝试匹配子表达式如果能够匹配则返回匹配成功的信息;
  • 逆序环视(lookbehind):作为表达式的而一部分,顺序环视顺序(从右至左)查看文本,尝试匹配子表达式如果能够匹配则返回匹配成功的信息;

注意:

  • 环视功能不是所有语言都支持,下面演示的以perl和grep为主;
  • 环视是不会占用字符的,即检查子表达式是否匹配,但它只寻找能够匹配的位置而不是真正的占用;环视不消耗字符也就是说在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
  • 顺序环视功能的结合顺序非常重要,由于是对于位置的确立下一步环视字符串之后才会正式匹配下一步中的字符串;
  • 逆序环视功能的结合顺序不重要,因为它并没有占用任何字符(并且使用\b锚定位),所以变换顺序并没有影响;无论是先监测左边还是再检测右边;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(?=pattern) #肯定型顺序环视(positive lookahread)(从左向右)  正向预查(能匹配pattern)
#例如(?=\d)表示如果当前位置 右边字符 是数字则匹配成功;
#例如'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。

(?!=pattern) #否定型顺序环视(negativ lookahread)(从左向右) 负向预查(不能匹配pattern)
#例如(?!=\d)表示如果当前位置 右边字符 不能是数字则匹配成功;
#例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的

(?<=pattern) #肯定型逆序环视(从右向左)查看文本 反向肯定预查与正向肯定预查类似,只是方向相反。注意空格
#例如(?<=\d)表示如果当前位置 左边字符 是数字则匹配成功;(?<=19)99 则匹配1999后面的99
#例如Windows( ?<=95|98|NT|2000|10)能匹配“98/NT/2000/10/Windows”中的“Windows”,但不能匹配“95Windows”中的“Windows”,软件不一定全部支持
perl -l -e '$str="Windows2000 95Windows 2000Windows Windows95";if($str =~ s/Windows( ?<=95|98|NT|2000|10)/NOW/g){print "匹配成功 $str"}'
# 匹配成功 NOW 95Windows 2000Windows Windows95

(?<!pattern) #肯定型逆序环视(从右向左)查看文本;
#例如(?<!\d)表示如果当前位置 左边字符 不能是数字则匹配成功;(?<!19)99 则匹配非1999后面的99,比如这时匹配2099中的99
#例如Windows( ?<!95|98|NT|2000|10)能匹配“95Windows”中的“Windows” 不能匹配“98/NT/2000/10/Windows”中的“Windows”
WeiyiGeek.

WeiyiGeek.

基础示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#示例0.分顺序环视
#1.大前提WeiyiGeek字符串不存在就无法匹配,如果存在顺序环视中指定的字符串再进行后面的匹配
perl -l -e '$str = "I name is WeiyiGeek, now study Regular expression";if($str =~ m/(?=WeiyiGeek)Weiyi/){print "顺序环视匹配成功: $str"}else{print "匹配失败"};'
顺序环视匹配成功: I name is WeiyiGeek, now study Regular expression
#使用grep进行演示
echo "My name is WeiyiGeek program" | grep -oP "(?=WeiyiGeek)Weiyi"
Weiyi

#2.将WeiyiGeek 转变成为 Weiyigeek,由于不和顺序环视中的匹配则不进行下一步的匹配;
perl -l -e '$str = "I name is Weiyigeek, now study Regular
expression";if($str =~ m/(?=WeiyiGeek)Weiyi/){print "顺序环视匹配成功: $str"}else{print "顺序环视匹配失败"};'
顺序环视匹配失败

#3.给perl正则加上一个不区分大小匹配则成功
perl -l -e '$str = "I name is Weiyigeek, now study Regular expression";if($str =~ m/(?=WeiyiGeek)Weiyi/i){print "顺序环视匹配成功: $str"}else{print "匹配失败"};'
顺序环视匹配成功: I name is Weiyigeek, now study Regular expression

#4.加上替换功能,将WeiyiGeeks转换成为WeiyiGeek's (注意这里需要对’转义)
perl -l -e '$str = "My Name is WeiyiGeeks"; $str =~ s/\bWeiyiGeek(?=s\b)/WeiyiGeek\047/g; print $str'
perl -l -e '$str = "My Name is WeiyiGeeks"; $str =~ s/WeiyiGeek(?=s\b)/WeiyiGeek\047/g; print $str'
# My Name is WeiyiGeek's


#示例2.逆序环视
#比如实现上面4需求,但是它又非常特殊实际上没有匹配任何字符,只是匹配了我们希望插入'的位置(逆序和顺序综合使用确定位置)
perl -l -e '$str = "My Name is WeiyiGeeks"; $str =~ s/(?<=\bWeiyiGeek)(?=s\b)/\047/g; print $str'
perl -l -e '$str = "My Name is WeiyiGeeks"; $str =~ s/(?=s\b)(?<=\bWeiyiGeek)/\047/g; print $str' #与上表达式相同只是颠倒了两个环视属顺序而已
# My Name is WeiyiGeek's


#示例3.综合示例(金额显示个数),下面将三个一组,右边数字的个数正好是3的倍数位置;再第一个数字之前加入逗哈所以我们添加(?<=\d)来限定匹配的位置
perl -l -e '$str = "prices 1546782457"; $str =~ s/(?<=\d)(?=(\d\d\d)+$)/,/g; print $str'
prices 1,546,782,457


#示例4.匹配后面的文本56前面不能是4,后面必须是9组成,因此可以匹配如下文本 5569 ,但是与4569不匹配
$ perl -E 'if("5569" =~ m/(?<!4)56(?=9)/){print "匹配成功"}else{print "匹配失败"}'
匹配成功
$ perl -E 'if("4569" =~ m/(?<!4)56(?=9)/){print "匹配成功"}else{print "匹配失败"}'
匹配失败


#示例5.不通过逆序/顺序环视添加都逗号
#使用环视代替\b (前则左边不能匹配单词字符集,右边能够匹配单词字符集) | (后者左边能够匹配单词字符集,右边不能够匹配单词字符集)
'(?<!\w)(?=\w) | (?<=\w)(?!\w)' #多此一举了
'(?!\d)' #替代 \b 和 $

perl -l -e '$str = "prices 1546782457"; $str =~ s/(\d)(?=(\d\d\d)+(?!\d))/$1,/g; print $str'
perl -l -e '$str = "prices 1546782457"; while($str =~ s/(\d)((\d\d\d)+\b)/$1,$2/g){}; print $str' #采用循环不进行任何操作重复这个循环,知直到匹配失败;
prices 1,546,782,457


进制与unicode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
\xn	  匹配n其中n为十六进制转义值,十六进制转义值必须为确定的两个数字长
#例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。

\num 匹配num其中num是一个正整数
#例如'(.)\1' 匹配两个连续的相同字符。

\n 标识一个八进制转义值或一个向后引用
#如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

\nm 标识一个八进制转义值或一个向后引用
#如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。
#如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。
#如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。

\nml 如果n为八进制数字(0-7),且m和l均为八进制数字(0-7),则匹配八进制转义值nml

\un 匹配n其中n是一个用四个十六进制数字表示的Unicode字符。
#例 \u00A9 匹配版权符号 (?)。

基础示例:

1
2
#\xn匹配相近的两个ascll的Hex
例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”,正则表达式中可以使用十六进制的ASCII编码

WeiyiGeek.xn

WeiyiGeek.xn

1
2
3
4
5
如果\n之前至少n个获取的子表达式,则n为向后引用否则,如果n为八进制数字(0-7),则n为一个八进制转义值的Ascll
#如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm

\nml 就是三位数的八进制表示Ascll
\un 例如\u00A9匹配版权符号(&copy;),用十六进制表示的Unicode
WeiyiGeek.进制

WeiyiGeek.进制


(?P=name) 引用别名为分配到字符串中.
(?P\d)abc(?P=Id) #未成功
匹配:1abc1 5abc5
(?p:xxx) (xxx)不分组版本,用于使用’|’ 或后接数量词
若要防止匹配被保存以备将来使用,请在括号内正则表达式模式之前放置 ?:


常用正则表达式

示例1.处理HTML标记
描述:对于处理HTML我们需要确保原始文件中的 ‘&’ ‘<’ 和 ‘>’ 字符不会出错,把它们转换为对应的HTML编码(&amp / &lt / &gt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#示例1.html标签
<\s*(\S+)(\s[^>]*)?> #<html>
<\s*(\S+)(\s[^>]*)?> [\s\S]* <\s*\/\1\s*> #<html></html>

#示例2.防止XSS以及HTML标签注入
$input =~ s/&/&amp;/g;
$input =~ s/</&lt;/g;
$input =~ s/>/&gt;/g;

#分割段落
$text =~ s/^[ \t\r]*$/<p>/mg
$text =~ s/^\s*$/<p>/mg

#将Email地址转换成为超链接模式;
$email = [email protected]
$email =~ s/\b(username RegExp\@host RegExp)\b/<a href="mailto:$1">$1<\/a>/g;

示例2.常用正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
移动电话: /^1[3456789]\d{9}$
#身份证正则:
//身份证正则表达式(15位)
isIDCard1=/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
//身份证正则表达式(18位)
isIDCard2=/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;
身份证正则合并:(^\d{15}$)|(^\d{17}([0-9]|X)$)
网络链接:(h|H)(r|R)(e|E)(f|F) *= *('|")?(\w|\\|\/|\.)+('|"| *|>)?
邮件地址:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
图片链接:(s|S)(r|R)(c|C) *= *('|")?(\w|\\|\/|\.)+('|"| *|>)?
IP地址:(\d+)\.(\d+)\.(\d+)\.(\d+)
中国电话号码(包括移动和固定电话):(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}
中国邮政编码:[1-9]{1}(\d+){5}
中国身份证号码:\d{18}|\d{15}
整数:\d+
浮点数(即小数):(-?\d*)\.?\d+
任何数字 :(-?\d*)(\.\d+)?
中文字符串:[\u4e00-\u9fa5]*
双字节字符串 (汉字):[^\x00-\xff]*