正则表达式学习笔记

正则表达式学习笔记

(原创内容,转载请注明来源,谢谢)

首先,学习正则表达式,很推荐一篇博客,http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html,deerchao写的《正则表达式30分钟入门教程》,看完他的文章,基本上可以在实际中使用正则表达式,本文是结合此博客和一些其他书籍的内容的学习笔记。

一、基础内容

我认为的基础内容包括以下7点,掌握后可以使用正则匹配很多内容。

1、位置

正则表达式表示位置的字符有^(表示字符串开始)、$(字符串结束)、\b(字符串开始或结束)。

在明确需要匹配的位置的情况下,建议使用^、$,因为其会加快字符串的匹配速度。

2、数量

正则表达式表示数量的主要有*(匹配任意次)、?(匹配0次或1次)、+(匹配1次或多次)、[](中括号内的内容匹配其中一个一次)、{m,n}(匹配m至n次,n省略则匹大于或等于m次,逗号也省略则匹配m次)。

3、字符组

字符组为使用一些特殊的方式表示一组同样规律的内容。\d表示0-9任意一个数字,

\s表示任意个空白字符(空格),\w表示任意大小写字母、数字、下划线、中文。.(点)表示换行符以外的任意内容。

字符组和数量常常组合起来使用,如匹配四位数字可以用\d{4}。

4、反义

^符号用在正则的第一个位置表示字符串的开始,但是用在[]内部则表示非,例如[^\d]表示匹配1个不是数字的字符。其他还有\W(表示非\w)、\D(表示非\d)、\S(表示\s)、[^abc]表示匹配abc以外的字符。

5、转义

转义使用反斜杠\,这个和很多程序语言相同。即\\匹配\,\.匹配.等。

6、分支

分支符号为|,和程序语言中的||意思相似,表示或的意思。例如要匹配my和mine,可以使用m(y|ine)进行匹配。

7、分组

分组采用()(小括号)把内容放在里面,通常分组后可以加上表示数量的词,进行批量匹配。例如要匹配的内容是三个数字加一个字母a,一共匹配10次,可以用(\d{3}a){10}。

二、进阶内容

除了上述内容,正则表达式提供了一些高级的功能,让匹配更加全面与方便。

1、捕获

1) (?<name>exp),该含义为匹配表达式exp,并将其命名为name,后面的匹配中可以用\k<name>表示匹配到的内容。

例如,(?<myname>\d{4})\w?\k<myname>,表示把第一次匹配到的4个数字存在myname内,后面就用\k<mynname>再次匹配即可。

2) 捕获还有其他写法,如(exp),表示不给exp取名字,该情况下会保存在系统默认名字内,从1开始编号。例如(\d)\w(\d{5})\w\1\w\2,表示第一次捕获的一个数字存在\1内,第二次捕获的五个数字存在\2内。

3) 因此,在正则表达式中,括号应当慎用,因为每个括号正则都会将其捕获,并进行存储,如果在长字符串匹配的情况下,又使用了大量的括号,将占用较多存储空间。另外,如果不需要捕获内容,可以使用(?:exp),表示不捕获文本,也不进行编号。

2、零宽断言

零宽断言也是类似$、^等表示位置的字符,但是对该位置上的字符有一定的要求。主要有四个表达方式。

1) (?=exp),表示该位置的内容要满足exp的要求时,匹配exp之前的内容。例如\w+(?=ing),会匹配doing的do。

2) (?<=exp),表示该位置的内容要满足exp的要求时,匹配exp之后的内容。例如\w+(?<=re),会匹配reading的ading。

3) (?!exp),表示该位置的内容不是exp时,匹配exp之前的内容。例如\b\w+(?!ing)\b,会匹配不含ing结尾的任意单词。

4) (?<!exp),表示该位置的内容不是exp时,匹配exp之后的内容。例如\b\w+(?!re)\b会匹配任意不是以re开头的单词。

上述内容中,3)、4)又称为负向零宽断言。

3、注释

(?#comment)表示注释,不会被解析,仅仅是便于其他人员查看正则表达式。

4、懒惰匹配

1) 懒惰匹配表示匹配尽量少的内容,在匹配符后面加上一个?即可。*?表示重复任意次,但是尽可能的少重复;{10,}表示重复10次以上,但是尽可能少重复。其他数量词加上?也一样,表示满足基本条件的情况下尽可能少匹配。

例如,a.*?b在字符串abaab中会匹配到ab。

2) 与懒惰匹配相对应的,就是贪婪匹配,在不加?情况下,前面说的内容都是贪婪匹配。

3) 为了使程序匹配速度更快,在确定只需要懒惰匹配的情况下,需要加上?,可以最快匹配到需要的内容。

5、优先级问题

优先级从高到低,依次是:

1) \

2) ()、(?=)、(?=)、[]

3) *、+、?、{n}、{n,}、{n,m}

4) ^、$、任意字符

5) |

三、PHP正则表达式匹配函数

1、preg_math

官方文档int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

常用到前三个参数,$pattern表示匹配的模式,$subject表示需要匹配的字符串,如果提供了参数matches,它将被填充为搜索结果。$matches[0]将包含完整模式匹配到的文本,$matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。

函数返回:pattern 的匹配次数。它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。

2、preg_match_all

官方文档int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int$offset = 0 ]]] )

前三个参数和preg_math一样,返回完整匹配次数(可能是0),或者如果发生错误返回FALSE。该函数匹配成功一次后,会从匹配成功的最后一个位置开始,继续往后匹配。

3、常用模式

preg_math和preg_math_all的$pattern,需要输入的字符串都是 ‘%exp%’,即在正则表达式的基础上,前后加上两个%。通常来说,不使用%,而用其他符号也可以,只需要保证前后一致即可。实际工程中,为了项目统一,最好定一个一致的号码。

1) 忽略大小写

$pattern = ‘%exp%i’,即在第二个%后面加一个字母i即忽略大小写匹配。

2) 点号通配模式

点号通配模式表示元字符.(点)忽略换行。使用方法是$pattern= ‘%exp%s’

3) 多行模式

多行模式表示,当$pattern是多行内容时,如果加上$、^,该模式下,会将$、^之间的内容当成一行内容,忽略字符串当中的换行\n。使用方法是$pattern = ‘%exp%m’

4) 懒惰模式

类似于正则表达式的懒惰模式,使用方法是$pattern = ‘%exp%U’

5) 结尾限制模式

该模式下,结尾不能有换行,否则匹配失败。使用方法是$pattern = ‘%exp%D’

6) 支持UTF-8转义表达方式

如果汉字等被用UTF-8编码,则需要开启此模式进行匹配。使用方法是$pattern = ‘%exp%u’

四、实际应用

1、校验

如手机号校验,要判断手机号是否为移动的号码,即要确定开头为135-139、150-151、157-159、182、183、188的手机号,表达式如下:

(?:13[4-9]|15[01789]|18[238])\d{8}

2、数据安全

当给用户提供输入框时,用户可能往里面输入js代码对网站进行破坏,这个称为XSS攻击,因此可以用正则表达式把所有的<>或者</>去掉。表达式如下:

<\/?[^>]+>

3、URL重定向

在Apache和Nginx中,经常需要配置url的rewrite,可以把php后缀的文件重定向到html后缀的文件中,这样做便于搜索引擎的检索。

假设需要把test.php?name=a&page=1重定向为test_a_1.html,在apache的.htaccess中,可以如下方式:

RewriteEngine on

RewriteRule index.html index.php

RewriteRule test_([a-z]+)(\d?)\.htmltest.php?name=$1&page=$2[NC]

NC表示忽略大小写,rewriteengineon是开启rewrite的意思。

五、PHP正则表达式的优化

当字符串很长,需要匹配的模式串也很长的时候,需要尽可能的对正则表达式进行优化,否则会降低程序运行速度。

1、满足匹配前提下少用|

|符号效率较低,需要逐个进行匹配,例如[abc]和[a|b|c],|会把内容分别进行匹配。

2、限定量词优先

在确定需要匹配次数的情况下,尽量不要使用*、+、{n,}等不限定长度的量词,否则会进行多次的查找。

3、优先用preg_match/命中率最高的匹配项放最左侧

因为其匹配到就停止,而preg_match_all会把全部内容匹配完。同样,在多个匹配条件情况下,把最有可能命中的情况放在最左侧,则匹配到就不会继续往后匹配。

4、合理使用括号

括号会占用存储空间,大量匹配的情况下慎用。

5、使用PHP自带的一些函数

1) 当可以确定需要的字符串的位置时,尽量使用字符串匹配函数,即str开头的函数,匹配速度更快。

2) 需要匹配PHP的源码,可以安装使用PHP自带的Tokenizer分析函数,可以准确的分析PHP的变量、常量、类名、方法名等。

3) 解析URL时,可以用PHP自带的parse_url()函数,该函数可以把url的类型、host、path、query等输出。

4) 获取HTTP头,可以使用PHP自带的get_headers()函数,该函数可以捕获到HTTP头的信息,并用数组方式返回。

5) 验证邮箱信息、URL信息、数据类型等,均可以安装使用PHP的filter_var函数,该函数可以使用特定的过滤器过滤一个变量。

六、验证正则表达式的正确性

网上有很多验证工具,我个人比较喜欢的是http://tool.lu/regex/

——written by linhxx 2017.07.05

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-07-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏web前端教室

javascript 数组的深复制和浅复制

这段时间忙的我是欲仙欲死,导致公众号断更了好几天。 但收获也是巨大的,对于JS的一些应用有了一些新的理解,以后我慢慢写出来。 今天简单的写一个javascrip...

1825
来自专栏IMWeb前端团队

bash 的变量和参数

对一个编程脚本来说,最最基础的当然是变量。 对大多数开发者来说,变量也是最不值得的大说特说的。 但 bash 里的变量有一些特别的地方值得说说,谨防跌坑。 基本...

1670
来自专栏python小白到大牛

零基础学习python编程不可错过的学习总结,小白福利!

通过以上可以看到我们写的很贱的程序随便保存了一个.txt结尾的格式,竟然也执行了,并没有按照统一要求的.py格式来设计, 那是不是说明后缀名可以说是任意的呢?理...

1103
来自专栏程序生活

浅谈Python内置函数chr、ord简介chrord学习资料

1413
来自专栏编程

【C语言编程锦囊·连载49】如何进行字符串的比较?

问题阐述 字符串的比较,就是看两个字符串哪个大,哪个小。比较的原则是对两个字符串进行逐个字符的比较。直到有不相等的字符为止。例: “abcd” “abxa” 这...

1706
来自专栏xcywt

《Linux命令行与shell脚本编程大全》第十七章 创建函数

可以将shell脚本代码放进函数中封装起来,这样就能在脚本中的任何地方多次使用它了。 17.1 基本的脚本函数 函数:是一个脚本代码块,可以为其命名并在代码中任...

17110
来自专栏Java帮帮-微信公众号-技术文章全总结

shell编程基础入门

shell编程基础入门 文章最后有下载shell学习指南电子书链接。 1.shell格式:例 shell脚本开发习惯 1.指定解释器 #!/bi...

3144
来自专栏Go入门系列

Golang 入门系列(二)Go语言基础语法及需要注意的坑

上一章节我们已经了解了 Go 环境的配置,不了解的,请查看前面的文章 https://www.cnblogs.com/zhangweizhong/p/94599...

30
来自专栏Python小屋

Python组合列表中多个整数得到最小整数(一个算法的巧妙实现)

'''程序功能: 给定一个含有多个整数的列表,将这些整数任意组合和连接, 返回能得到的最小值。 代码思路: 将这些整数变为相同长度(按最...

3036
来自专栏FreeBuf

Pwnable.tw刷题之Silverbullet破解过程分享

0x00背景介绍 之前加了学校的ctf社团之后开始学习binary方面的知识,跟着教程走完一遍之后学长推荐了pwnable来刷题,这篇文章就是pwnable上s...

3436

扫描关注云+社区