目錄
基本提取
提取包含指定内容的行
首頁 後端開發 php教程 php实战正则表达式(二):提取html元素

php实战正则表达式(二):提取html元素

Jun 23, 2016 pm 01:26 PM

这篇文章通过提取html元素介绍了正则表达式中模式修饰符、贪婪匹配与非贪婪匹配、Unicode模式、环视等知识点。
在阅读这篇文章前最好把同系列文章php实战正则表达式(一):验证手机号先仔细阅读一遍。

基本提取

有这样一个表格

用户名 职业
Kobe Bryant 篮球运动员
Jay Chou 歌手、词曲创作人、制作人、演员、导演
Lionel Messi 足球运动员

它的源码如下:

<table>  <thead>    <tr><th>用户名</th><th>职业</th></tr>  </thead>  <tbody>    <tr>      <td>Kobe Bryant</td><td>篮球运动员</td>    </tr>    <tr>      <td>Jay Chou</td><td>歌手、词曲创作人、制作人、演员、导演</td>    </tr>    <tr>      <td>Lionel Messi</td><td>足球运动员</td>    </tr>  </tbody></table>
登入後複製

现在要提取

第一个元素。最简单的正则表达式应该是这样:

\s+.*

其中

  • \s是php实战正则表达式(一):验证手机号介绍过的字符组简记法中的一个,代表回车符、空格、制表符等空白字符

  • 量词+表示它所修饰的字符或字符组出现次数大于等于1

  • 点号字符.在正则表达式中是一个特殊的元字符,它可以匹配“任意字符”

  • 闭标签

中的斜线/在php的正则表达式中是模式分隔符,所以需要转义来表示斜线字符。

但实际上这样一个表达式是无法从上面的

中提取第一个元素的

这里主要的问题是在默认情况下点号字符.无法匹配换行符\n。有两个方法可以解决这个问题:

  • 使用模式修饰符s,正则表达式为/

    \s+.*/s或(?s) \s+.*。模式修饰符s的作用就是让点号字符.可以匹配换行符。
  • 用[\s\S]或[\w\W]或[\d\D]代替点号字符.来匹配所有字符,正则表达式为

    \s+[\s\S]*

    关于模式修饰符(Pattern Modifiers),这里需要详细介绍一下(点击这里查看php支持的所有模式修饰符)。模式修饰符可以改变正则表达式的一些默认规则,常用的模式修饰符有i、s、U、u等,我们在后面会用到它们中的一些,这里不展开介绍每个模式修饰符的作用,后面用到了再具体介绍。这里主要对比一下/.../{modifier}与...(?{modifier})...两种表示方法的区别。

    .*/s (?s).*
    模式修饰符 /.../{modifier} ...(?{modifier})...
    示例 /
    名称(php手册) 模式修饰符 模式内修饰符
    名称(《正则指引》) 预定义常量 模式修饰符
    作用范围 整个正则表达式 不在分组(子表达式)中时,对它后面的全部正则表达式起作用;如果在分组(子表达式)中,则对它分组中的剩余部分起作用。在没有分组,且放在整个正则表达式最前面的时候相当于/.../{modifier}
    支持程度 支持所有模式修饰符 支持部分模式修饰符
    其他编程语言 可能不支持 一般都支持

    从上面的gif中可以看到提取的结果中有三个tr,而不是只有一个。这是因为正则表达式中量词默认是贪婪匹配,在这里,.*会匹配一切字符,直到最后没有字符再向前回溯,回溯到

    中的最后一个时与正则表达式中的相匹配,从而完成整个匹配过程,最后的结果也就是包含了三个。

    可以使用模式修饰符U指定整个正则表达式为非贪婪模式,也可以使用非贪婪匹配量词指定某一个量词为非贪婪模式:

    • 指定整个正则表达式为非贪婪模式:

      • /

        \s+.*/Us
      • 或(?Us)

        \s+.*
      • 非贪婪量词:
        /

        \s+.*?/s

        完整的贪婪量词(匹配优先量词)与非贪婪量词(忽略优先量词)见下表:

        贪婪量词 非贪婪量词 限定次数
        * *? 可能出现,可能不出现,出现次数没有上限
        + +? 至少出现1次,没有上限
        ? ?? 出现0次或1次
        {m,n} {m,n}? 出现次数大于等于m,小于等于n
        {m,} {m,}? 至少出现m次,没有上限
        {0,n} {0,n}? 出现0次-n次

        提取包含指定内容的行

        假设我们想把表格中有关于运动员的记录都提取出来,我们可能会使用/

        .*运动员.*/s这样的正则表达式。

        这个表达式在Unicode编码环境下可以匹配出结果,但是在GBK环境下就未必了。我们可以通过模式修饰符u来指定Unicode模式:

        /

        .*运动员.*/us

        在Unicode模式下,我们甚至可以使用码值来代替汉字:

        /

        .*\x{8fd0}\x{52a8}\x{5458}.*/us

        php正则中使用\x{hex}的形式来表示Unicode字符的码值,使用码值的好处是可以结合字符组来表示一段范围,如[\x{4e00}-\x{9fff}]表示匹配所有汉字字符。

        上面的表达式可以匹配出结果,但是却不正确。我们可以看到,它匹配了整个字符串的第一个

        到最后一个。
        直觉上,我们是想正则表达式先去匹配“运动员”,然后向左寻找最近的一个,向右寻找最近的一个。但事实上,正则表达式是从左往右匹配的,即从开始寻找,整个正则表达式的匹配情况见下表(空白字符没有显示出来)。
        表达式 匹配值
        /
        .* 用户名 职业
        Kobe Bryant 篮球
        运动员 运动员
        .*
        Jay Chou 歌手、词曲创作人、制作人、演员、导演
        Lionel Messi 足球运动员
        /us

        这里两个.*匹配到的字符都比预期要多。第二个.*匹配字符比预期多的原因是正则表达式默认是贪婪匹配模式,它会匹配剩余字符串中的每个字符,直到字符串的末尾,然后再向前回溯到最后一个

        ,可以通过指定非贪婪匹配模式来解决这个问题。但是第一个.*匹配字符比预期多是正常现象,因为正则表达式是从左向右匹配的,表达式中的匹配字符串中第一个 ,后面的.*则匹配剩余的所有字符,直到字符串的末尾,然后再向前回溯到“运动员”。

        我们先看看使用非贪婪匹配时的结果:

        可以看到,第二个.*匹配的字符已经是我们想要的了。那么,对于第一个.*匹配字符比预期多这个问题怎么解决呢?

        如果仅使用到目前为止我的文章中介绍的知识,也是有方法可以解决的。我们可以先从左到右匹配出所有的行(

        ...),方法是使用php中的preg_match_all函数结合非贪婪匹配模式;然后再遍历每一行,过滤出其中包含“运动员”的行即可。

        当然,我们也可以通过纯粹的正则表达式来解决这个问题。如果有一定正则表达式使用经验的朋友可能很容易联想到排除型字符组,我们介绍过字符组[...],它表示在同一位置可能出现的字符。而排除型字符组则表示在同一位置不能出现的字符,它的形式是[^...],通过紧跟在开方括号[后面的^来表示排除型字符组。例如,[^\d]表示匹配的字符是除了数字以外的任意字符。
        如果有排除型子表达式,类似于(^

        )*,我们只需要指定第一个.*把 排除就行了。但是很遗憾,正则表达式中没有排除型子表达式或者说排除型分组。这种情况下,我们只能使用环视

        /

        (.(?! ))*运动员.*/Us

        环视(look-around)不匹配任何字符,用来“停在原地,四处张望”。上面的表达式使用了否定顺序环视,它的形式是(?!...)。具体对于(.(?!

        ))*来分析,每当.匹配了一个字符后,就向右看看,如果当前匹配字符的右边没有出现 就匹配成功。

        完整的环视有:

        名字 记法 含义
        肯定顺序环视 (?=...) 向右看看,右边出现了环视中的内容才匹配
        否定顺序环视 (?!...) 向右看看,右边不出现环视中的内容才匹配
        肯定逆序环视 (? 向左看看,左边出现了环视中的内容才匹配
        否定逆序环视 (? 向左看看,左边不出现环视中的内容才匹配

        由于上面的正则表达式有一个分组(子表达式),所以匹配的结果除了下标0,还有下标1,这里下标1的结果其实没有什么用,我们可以用之前介绍过的非捕获分组

        /

        (?:.(?! ))*运动员.*/Us

        我们的真正目的是提取所有包含“运动员”的行,而上面只提取了第一个,所以需要将preg_match函数换成preg_match_all。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1663
14
CakePHP 教程
1420
52
Laravel 教程
1315
25
PHP教程
1266
29
C# 教程
1239
24
說明PHP中的不同錯誤類型(注意,警告,致命錯誤,解析錯誤)。 說明PHP中的不同錯誤類型(注意,警告,致命錯誤,解析錯誤)。 Apr 08, 2025 am 12:03 AM

PHP中有四種主要錯誤類型:1.Notice:最輕微,不會中斷程序,如訪問未定義變量;2.Warning:比Notice嚴重,不會終止程序,如包含不存在文件;3.FatalError:最嚴重,會終止程序,如調用不存在函數;4.ParseError:語法錯誤,會阻止程序執行,如忘記添加結束標籤。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? 說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? Apr 17, 2025 am 12:06 AM

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

什麼是HTTP請求方法(獲取,發布,放置,刪除等),何時應該使用? 什麼是HTTP請求方法(獲取,發布,放置,刪除等),何時應該使用? Apr 09, 2025 am 12:09 AM

HTTP請求方法包括GET、POST、PUT和DELETE,分別用於獲取、提交、更新和刪除資源。 1.GET方法用於獲取資源,適用於讀取操作。 2.POST方法用於提交數據,常用於創建新資源。 3.PUT方法用於更新資源,適用於完整更新。 4.DELETE方法用於刪除資源,適用於刪除操作。

解釋self ::,parent ::和static :: in php oop中的區別。 解釋self ::,parent ::和static :: in php oop中的區別。 Apr 09, 2025 am 12:04 AM

在PHPOOP中,self::引用當前類,parent::引用父類,static::用於晚靜態綁定。 1.self::用於靜態方法和常量調用,但不支持晚靜態綁定。 2.parent::用於子類調用父類方法,無法訪問私有方法。 3.static::支持晚靜態綁定,適用於繼承和多態,但可能影響代碼可讀性。

PHP如何安全地上載文件? PHP如何安全地上載文件? Apr 10, 2025 am 09:37 AM

PHP通過$\_FILES變量處理文件上傳,確保安全性的方法包括:1.檢查上傳錯誤,2.驗證文件類型和大小,3.防止文件覆蓋,4.移動文件到永久存儲位置。

See all articles