PHP和正则表达式:初学者的基础

预期“ PHP后端开发人员”课程以及相关课程“ Framework Laravel”中的新主题将开始,我们希望分享自由作者编写的文章。

注意! 本文与课程计划无关, 仅对初学者有用。 要获得更深入的知识,我们邀请您访问免费的为期两天的在线密集课程,主题为:“创建Telegram-bot以在机构中订购咖啡并在线付款 紧张的第二天将在这里举行。




大家好! 即将到来的[20]{2,}0 。 今天,我想谈谈一个有时从“是的,如果您已经有了现成的解决方案,为什么还需要学习所有这些知识”到“还可以学习全部Perl?”的笑话主题。 但是,随着时间的流逝,许多程序员开始精通正则表达式,而在哈布雷(Habré)上,没有一个关于该主题的新文章( 尽管正则表达式最近变化不大 )。 现在该写另一个了!


正则表达式与其具体实现隔离


正则表达式(英语表示为RegExregex )是一种用于研究和处理文本的各种选项的工具:搜索,检查,搜索和替换由字母或数字(或其中的任何其他字符)组成的元素包括特殊字符和标点符号)。 最初,正则表达式是从50年代在数学领域进行的科学研究环境中诞生的。

几十年后,这些原理和思想被转移到UNIX操作系统环境中(特别是它们包含在grep实用程序中),并以Perl编程语言实现,该语言在Internet诞生之初就广泛用于后端(至今已被使用,但如今已经很少使用)了例如表单验证。



如果它们看起来很简单,那么为什么乍一看它们却如此恐怖呢?

实际上,任何表达式都可以是“正则表达式”,并且可以用于检查或搜索任何字符。 例如,词Pavelexample@mail.ru当然也可以用作常规,只是在相当狭窄的范围内。 要在PHP环境中测试正则表达式的性能而无需启动服务器或托管,您可以使用以下在线服务 (该服务不适用于俄语字符的处理)。 首先,我们只使用Pavel作为正则表达式。

假设我们有以下文本:

帕维尔非常了解。 帕维尔使用nginx,但他不是漫步者。

现在,正则表达式已经找到了单词Pavel的两种情况。 很棒,但是听起来并不是很有用(除非出于某些原因,您试图通过Vim和Python分析诸如《战争与和平》中“ 先生 ”一词的提法之类的内容,但是我对您没有任何疑问)。

表达变异性

如果您的正则表达式是可变的(例如,您只知道其中的一部分,并且需要查找从2000年开始到2099年结束的年数),那么我们可以使用以下正则表达式: 20 ..

文字:年轻作家写很多东西。 例如,出生于2002年的作家与2008年2012年大不相同

在这里,借助正则表达式,我们可以找到所有年份,但是到目前为止,这没有任何意义。 最有可能的是,我们不需要2012年以后的年份(尽管可能会冒犯8岁以下的年轻作家,但现在不应该这样)。 值得研究字符集,但稍后再讨论,因为现在我们将讨论正则表达式的另一个重要部分:转义元字符。

想象一下,我们需要查找扩展名为.doc的文件的出现次数(假设我们仅导出某些上传到数据库的文件)。 但是,点仅表示任何字符吗? 那该怎么办呢?
在这里,用反斜杠转义元字符对我们有帮助。 现在,表达式\.doc将足以搜索任何带有扩展名.doc文本:

正则表达式: \.doc

文字:kursach.doc, nepodozritelneyfail.exeshaprgalka.rtf docshaprgalka.rtf doc

如您所见,我们可以在列表中成功找到扩展名为.doc的文件数。 但是,我们无法使用此正则表达式提取完整文件名,例如,将其提取到数组中。 现在该看看字符集了。

匹配整套字符

在正则表达式中,使用元字符-方括号[ ]来提供与集合的匹配。 可以将任意两个ASII字符指定为范围的开始和结束。 对于一个简单的实现,假设我们要查找扩展名为.jpg所有编号为0到9的文件。

正则表达式: [0-9]\.jpg

文字: 1.jpg2.jpg3.jpg ,photo.jpg,anime.jpg, 8.jpg ,jkl.jpg

值得注意的是,我们的正则表达式不会覆盖超过1位的文件名。 关于多项选择的选择会略低一些,但是现在想象一下,我们突然需要实现相反的结果。 添加元字符^ (相反,它在正则表达式中具有多达两个函数)。 要将其用作例外,您需要将其完全添加到我们的集合中:

正则表达式: [^0-9]\.jpg

文字:1.jpg,2.jpg,3.jpg,phot o.jpg ,anim e.jpg ,8.jpg,jk l.jpg

但是如果没有多重选择,这些当然是劣等的表达。

有用的表

这是一个元字符表:

\将元字符转义为常规字符
^在行的开头搜索特定字符(但仅当您从集合[]中排除该字符时)
$行尾
|另类
()分组
\ w所有字母数字字符(由于某些原因,许多手册在数字字符上不一致)
\ W同一件事,正好相反
\ s任何空格
\ S任何非空白


空格元字符表
[\ b]单字符返回
\ f页面翻译
\ n换行
\ r回车
\ t制表
\ v垂直标签


多项选择:进行简单验证


掌握了所学的知识之后,我们将尝试制作一个正则表达式,以查找例如少于3个字母的单词(反垃圾邮件的标准任务)。 如果我们尝试使用以下正则表达式- \w{1,3} (其中元字符\w表示任何字符,大括号表示从多少到多少的字符数,那么我们将突出显示一行中的所有字符-您需要以某种方式指定文本中单词的开头和结尾,为此,我们需要元字符\b

正则表达式: \b\w{1,3}\b:

文字:好词



还不错! 现在,少于三个字母的单词将无法进入我们的数据库。 让我们看一下邮件地址的验证:

正则表达式: \w+@\w+\.\w+

要求:电子邮件的开头应该是任何字符(数字或字母,因为电子邮件通常只包含数字)。 然后是@符号,然后是任意数量的字符,然后是转义的点(即只是一个点)和第一级域。

更详细地考虑字符重复。

现在,让我们仔细看看如何在正则表达式中重复字符。 例如,您想在文本中找到2到6之间的任何数字组合:

正则表达式: [2-6]+

文字:这是89个不同的234位数字24

让我给您一张所有元字符量词的表格:

*字符重复0,广告无限
+从1重复到无穷
{n}精确重复n次
{n,}从n到无穷大
{n1,n2}精确地从n1到n2倍
0或1个字符,不再


应用量词没什么复杂的。 除了一个警告:贪婪和懒惰的量词。 表格如下:

**?
++?
{n,}{n,}?


惰性量词与贪婪的量词的不同之处在于,它们捕获的字符数最少而不是最大。 想象一下,我们有一个任务来查找所有h1-h6标头标签及其内容,并且其余文本不受影响(我故意输入了不存在的h7标签,以免遭受转义Habra标签的困扰):

正则表达式:<h [1-7]>。*?<\ / H [1-7]>

文本: < h7 >您好</ h7 > lorem ipsum avada kedavra < h7 >购买< /h7 >

一切都成功进行,但这仅归功于惰性量词。 在使用贪婪量词的情况下,标记之间的所有文本都会突出(我认为这不需要说明)。

字符串边框

我们上面已经使用过的字符串的边界。 这是更详细的表:

\ b词边界
\ B不是单词边界
\ A行首
\ Z行尾
\ G行动结束


使用子表达式

正则表达式中的子表达式是使用group metacharacter ()
这是一个可以普遍找到IP地址的各种变体的正则表达式示例。

正则表达式:(((25 [0-5])|(2 [0-4] \ d)|(1 \ d {2})|(\ d {1,2}))\。){3} ((((25 [0-5] |(2 [0-4] \ d)|(1 \ d {2})|(\ d {1,2}))))

文字: 255.255.255.255只是一个地址
191.198.174.192维基百科
87.240.190.67 vk
31.13.72.36脸书

它使用逻辑运算符| (或),这使我们可以编写与IP地址的编译规则匹配的正则表达式。 IP地址必须包含1到3位数字,其中三个数字可以从1到2开头(或者第二个数字必须在0到4之间),或者以25开头然后是3位数结果在0到5之间。而且,每个数字组合之间必须有一个点。 使用上面的表格,尝试在顶部破译正则表达式。 一开始的正则表达式会让您感到厌烦,但长并不意味着复杂。

展望未来

要查看某些字符的任何组合的表达式,请指定一个模式,通过该模式可以检测到匹配项,但不会返回。 本质上,向前看定义了一个子表达式,因此它是相应形成的。 向前看的语法模式由一个以?=开头的子表达式组成,然后均等地跟随要匹配的文本。

这是一项特定的任务:密码必须至少包含7个字符,并且必须至少包含一个大写字母和数字。 在这里,一切都将变得更加复杂,因为用户应该能够将大写字母放在句子的开头和中间(并且该字母应该重复相同的内容)。

因此,我们需要期待表达。 此外,我们需要将标志分成几组。 我想将其大小限制为8到22个字符:

正则表达式:/ /^(?=.*[az])(?=.*[AZ])(?=.*\d)[a-zA-Z\d]{8,}$/

文字: Qwerty123
Im789098
弱密码

PHP正则表达式工作的功能


要了解正则表达式在PHP中的工作方式,请查看官方PCRE文档(Perl兼容正则表达式)中的功能,该文档可在官方网站上获得。 该表达式必须用定界符括起来,例如用正斜杠括起来。

任意字符都可以是分隔符,字母数字,反斜杠“ \”和零字节除外。 如果定界符出现在模式中,则必须转义\。 作为分隔符,组合来自Perl:(),{},[]。

PHP使用什么功能? PCRE软件包提供以下功能来支持正则表达式:

  • preg_grep() -执行搜索并返回匹配项数组。
  • preg_match() -使用正则表达式搜索第一个匹配项
  • preg_match_all() -使用正则表达式执行全局搜索
  • preg_quote() -接受模板并返回其转义版本
  • preg_replace() -执行搜索和替换操作
  • preg_replace_callback() -也执行搜索和替换操作,但它们使用回调-任何特定替换的函数
  • preg_split() -将字符串拆分为子字符串


修饰词i安排不区分大小写的匹配。
使用m修饰符,可以激活多行文本处理模式。

替换字符串可以作为PHP代码计算。 要激活此模式,请使用e修饰符。

所有preg_replace()preg_replace_callback()preg_split()支持一个附加参数,该参数引入了对最大替换数或分区数的限制。

反向链接可以用$符号表示(例如,$ 1),在早期版本中,使用\符号代替$符号。
不使用元字符\ E,\ l,\ L,\ u和\ U(因此,本文中未提及它们)。

没有POSIX字符类,我们的文章将是不完整的,POSIX字符类也可以在PHP中使用(通常可以很好地提高常规的可读性,但并非所有的急着学习,因为它们经常破坏表达式的逻辑)。

[[:alnum:]]英文字母或数字的任何字母
[[:alpha:]]任何字母([a-zA-Z])
[[:空白:]]空格或字符代码0和255
[[:数字:]]任意数字([0-9])
[[:较低:]]英文字母的任何小写字母([az])
[[:上层:]]英文字母的任何大写字母([AZ])
[[:punct:]]任何标点符号
[[:空格:]]任何空格
[[:xdigit:]]任意十六进制数字([0-9a-fA-F])


最后,我将给出一个使用上述实现的PHP正则表达式的具体实现示例。 我还添加了用户名验证,以便他不能输入太短的字母组合(好吧,假设这些是昵称,而不是名称,名称短于两个字母):

  $pattern_name = '/\w{3,}/'; $pattern_mail = '/\w+@\w+\.\w+/'; $pattern_password = '/^(?=.*[az])(?=.*[AZ])(?=.*\d)[a-zA-Z\d]{8,}$/'; if (preg_match($pattern_name, $name) && preg_match($pattern_mail, $mail) && preg_match($pattern_password, $_POST['password'])) { #  ,  ,   ,   ,      } 


谢谢大家的关注! 当然,今天我们仅涉及正则表达式的一部分,并且可以撰写更多有关正则表达式的文章。 例如,我们没有讨论文本中相同单词重复搜索的实现。 但我希望所获得的知识足以有意义地编写我的第一个表单验证,然后再进行更复杂的事情。

按照传统,一些有用的链接:

MIT正则表达式备忘单
php regex 文档的官方部分。

仅此而已。 密集见!
紧张的第二天将在这里举行

Source: https://habr.com/ru/post/zh-CN484048/


All Articles