ホームページ  >  記事  >  バックエンド開発  >  PHP正規表現に関する注意事項

PHP正規表現に関する注意事項

WBOY
WBOYオリジナル
2016-06-23 13:18:55855ブラウズ

正規表現とは何ですか?

コンピューターでは、必要なファイルを見つけるために (ワイルドカード文字) をよく使用します。たとえば、*.doc (* は 0 個以上の文字と一致することを意味します)。正規表現もテキストの一致に使用されるツールですが、より強力です。 PHP マニュアルから文を引用すると、次のようになります。 正規表現は、ターゲット文字列に左から右に一致するパターンです。ほとんどの文字は、それ自体に一致するパターンを表します。

正規表現について予備的に理解していただくために、いくつかの簡単な例を以下に示します。

hi  //匹配英文字符(忽略大小写) hi , HI , Hi , hI

\bhi\b  //匹配英文单词 hi  '\b'是正则里的一特殊字符(一种断言),表示单词边界

\bhi\b.*\bLucy\b  //匹配如:'hi my name is Lucy'  '.' 表示匹配除换行符以外的任意字符  '*' 是量词,表示重复零次或更多次

0\d{2}-\d{8}  //匹配如: 020-12345678  '\d' 匹配一个数字(0-9)    '{n}' 重复n次,如{2} {8}

上記の例では、 b 、 . 、 * 、 d 、 {2} はすべて特別な意味を持ちます。これについては以下で説明します。

PHP の正規構文

1. はじめに

PHP では、POSIX と PCRE の 2 種類の正規表現がサポートされています。 PHP 5.3.0 以降、POSIX 正規表現拡張機能は非推奨になりました。したがって、以下の説明は PCRE モードに基づいています。クリックすると、POSIX 正規表現との違いおよび perl との違いが表示されます。

2. デリミタ

PCRE 関数を使用する場合、パターンを閉じてデリミタで囲む必要があります。区切り文字には、英数字、バックスラッシュ、または空白文字以外の任意の文字を使用できます。一般的に使用される区切り文字は、スラッシュ /、ハッシュ記号 #、および否定記号 ~ です。次の例はすべて、正当な区切り文字を使用したパターンです。

/foo bar/#^[^0-9]$#+php+%[a-zA-Z0-9_-]%

パターン内で区切り文字を一致させる必要がある場合は、バックスラッシュでエスケープする必要があります。パターン内で区切り文字が頻繁に発生する場合は、読みやすさを向上させるために他の区切り文字を使用することをお勧めします。例:

/http:\/\//#http://#

3. メタ文字

正規表現の威力は、パターンを選択して繰り返す機能にあります。一部の文字には特別な意味が与えられており、それ自体を単に表すのではなく、パターン内で特別な意味を持つエンコードされた文字は メタ文字 と呼ばれます。
2 つの異なるメタキャラクターがあります。1 つはパターン内の角括弧の外側のどこでも使用でき、もう 1 つは角括弧内で使用する必要があります。

角括弧の外側で使用されるメタキャラクタは次のとおりです:

コードの説明 } パターン内の角括弧内の部分を「文字クラス」と呼びます。 文字クラスで使用できるメタ文字は次のとおりです: コード 説明 ^-
/ 一般に文字をエスケープするために使用されます
^ ターゲットの開始位置 (または複数行モードの行の開始位置) をアサートします。
$ ターゲットの終了位置 (または複数行モードの行末) をアサートします
. 改行を除く任意の文字と一致します (デフォルト)
[ 開始文字クラス定義
] 文字クラス定義の終了
| オプションの分岐の開始
( サブグループの開始タグ
) サブグループマーカーの終了
? a: 量指定子として、0 または 1 の一致を示します。 b: 量指定子の後に位置し、量指定子の貪欲な特性を変更するために使用されます。 ...
since 量指定子の終了タグを定義します
エスケープ文字
最初の文字 (角括弧内) として使用される場合のみ、文字クラスが反転

文字範囲をマーク

例:

  • baw*b は、文字 a で始まる単語、最初に単語の先頭の b、次に文字 a、その後に任意の数の任意の単語文字と一致します (単語文字とは、任意の文字、数字、アンダースコアを指します) ) w*、そして最後に単語の最後に b が付きます。
  • d+ は 1 つ以上の連続する数字と一致します。
  • ^d{5,12}$ は 5 ~ 12 桁に一致します。^ と $ が使用されるため、入力文字列全体を使用して d{5,12} に一致する必要があります。つまり、入力文字列全体が次のようになります。 5 ~ 12 桁の数字。
  • 4. エスケープ シーケンス (バックスラッシュ)

    バックスラッシュには 4 つの用途があります。詳細については、エスケープ シーケンス (バックスラッシュ) をクリックしてください。

    【1】エスケープ文字として、たとえば * 文字と一致させたい場合は、パターン内では * として記述します。これは、エスケープせずに文字が特別な意味を持つ場合に適用されます。 ただし、英数字以外の文字の場合は、元のテキストの照合に必要な場合、文字の前にバックスラッシュを追加して、それ自体を表すことを宣言することが常に安全です。バックスラッシュを一致させたい場合は、パターン内で \ を使用します。

    バックスラッシュは一重引用符で囲まれた文字列と二重引用符で囲まれた文字列で特別な意味を持ちます。そのため、バックスラッシュと一致させるには、パターンを \\ として記述する必要があります。理由は、まず文字列として使用され、バックスラッシュがエスケープされるからです。最後に、正規表現エンジンはバックスラッシュもエスケープされるものとみなします。したがって、1 つのバックスラッシュと一致するには 4 つのバックスラッシュが必要です。

    [2] 非印刷文字の表示エンコーディングの制御メソッドを提供します

    [3] 特定の文字クラスを記述するために使用されます

    コードの説明 d任意の 10 進数 D 任意10 進数以外の数値h任意の水平空白文字 (PHP 5.2.4 以降)H 任意の非水平空白文字 (PHP 5.2.4 以降) どれでも空白文字 S任意の非空白文字v任意の垂直空白文字 (PHP 5.2.4 以降)V任意の非垂直空白文字スペース文字 (PHP 5.2 以降) 4 )w Word の文字とは、任意の文字、数字、アンダースコアを指します。 W単語以外の文字
    【4】いくつかの簡単な主張。アサーションは、特定の位置で一致する必要がある条件を指定します。ターゲット文字列の文字は消費されません。バックスラッシュ アサーションには以下が含まれます:

    b 単語境界
  • B 非単語境界
  • A ターゲットの開始位置 (複数行モードから独立)
  • Z ターゲットの終了位置または末尾の改行 (複数行モードから独立) )
  • z ターゲットの終了位置 (複数行モードとは独立)
  • G ターゲット内の最初の一致位置
  • 5. 繰り返し/量指定子

    コードの説明 * 0 回以上繰り返し、同等to + 1 回以上繰り返し、 と同等? 0 回または 1 回繰り返し、{n} を n 回繰り返します {n、 }n回以上繰り返します{n,m}n〜m回繰り返します

    默认情况下,量词都是”贪婪”的,也就是说,它们会在不导致模式匹配失败的前提下,尽可能多的匹配字符(直到最大允许的匹配次数)。然而,如果一个量词紧跟着一个 ? 标记,它就会成为懒惰(非贪婪)模式, 它不再尽可能多的匹配,而是尽可能少的匹配。
    下面直接看示例,理解“贪婪”和“非贪婪”模式是怎么回事。

    对于字符串 "aa<div>test1</div>bb<div>test2</div>cc"正则表达式 "<div>.*</div>"    匹配结果 "<div>test1</div>bb<div>test2</div>"正则表达式 "<div>.*?</div>"   匹配结果 "<div>test1</div>"

    关于更多“贪婪”和“非贪婪”模式的介绍可查阅 http://php.net/manual/zh/regexp.reference.repetition.php

    6.字符类(方括号)

    PHP手册中的描述:

  • 左方括号开始一个字符类的描述,并以方中括号结束。单独的一个右方括号没有特殊含义。如果一个右方括号需要作为一个字符类中的成员,那么可以将它写在字符类的首字符处(如果使用了 ^ 取反,那么是第二个)或者使用转义符。

  • 一个字符类在目标字符串中匹配一个单独的字符;该字符必须是字符类中定义的字符集合的其中一个, 除非使用了 ^ 对字符类取反。如果^需要作为一个字符类的成员,确保它不是该字符类的首字符,或者对其进行转义即可。

  • 示例:

    [aeiou]    //匹配所有的小写元音字母[^aeiou]   //匹配所有非元音字母的字符[.?!]      //匹配标点符号(.或?或!)

    注意:^ 只是一个通过枚举指定那些不存在字符类之中的字符的便利符号。而不是断言, 它仍然会从目标字符串中消耗一个字符,并且如果当前匹配点在目标字符串末尾, 匹配将会失败。

    轻松地指定一个字符范围,范围操作以 ASCII 整理排序。它们可以用于为字符指定数值,比如 [\000-\037]

    [0-9]    //代表的含意与 '\d' 就是完全一致的[a-z0-9A-Z_]    //完全等同于 '\w' 如果只考虑英文的话

    下面是一个更复杂的表达式 \(?0\d{2}[) -]?\d{8}
    这个表达式可以匹配几种格式的电话号码,像 (010)88886666,或 022-22334455 ,或 02912345678 等。
    简单分析:首先是一个转义字符 \( ,它能出现 0 次或 1 次 ? ,然后是一个数字 0 ,后面跟着 2 个数字 \d{2} ,然后是 ) 或 - 或 “空格” 中的一个,它出现 0 次或 1 次,最后是 8 个数字 \d{8} 。

    7.分支 ( | )

    竖线字符用于分离模式中的可选路径。比如模式 gilbert|Sullivan 匹配 ”gilbert” 或者 ”sullivan”。竖线可以在模式中出现任意多个,并且允许有空的可选路径(匹配空字符串)。匹配的处理从左到右尝试每一个可选路径,并且使用第一个成功匹配的。如果可选路径在子组(下面定义)中,则”成功匹配”表示同时匹配了子模式中的分支以及主模式中的其他部分。

    回看上文里的一个例子 \(?0\d{2}[) -]?\d{8} 这个正则也能匹配 010)12345678 或 (022-87654321 这样的 “不正确” 的格式。其实我们可以利用分支就能解决这个问题,如下:

    \({1}0\d{2}\){1}[- ]?\d{8}|0\d{2}[- ]?\d{8} 这个表达式匹配 3 位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。

    使用分枝条件时,要注意各个条件的顺序

    8.内部选项设置

    正则表达式在不同的模式修饰符下匹配出的结果有可能不相同。它的语法是 :(?修饰符)

    比如,(?im) 设置表明多行大小写不敏感匹配。同样可以用它来取消这些设置,比如 (?im-sx) 设置了 “PCRE_CASELESS”,”PCRE_MULTILINE”,但是同时取消了 “PCRE_DOTALL” 和 “PCRE_EXTENDED”。如果一个字母即出现在 - 之前, 也出现在 - 之后,这个选项被取消设置。

    下面紧例举简单的示例,想要了解更多可点击 内部选项设置 和 模式修饰符

    示例:/ab(?i)c/ 仅仅匹配 ”abc” 和 ”abC”

    9.子组(子模式)

    子组通过圆括号分隔界定,并且它们可以嵌套。

    示例:

    字符串:"the red king"正则表达式:((red|white) (king|queen))匹配结果:array("red king", "red king", "red", "king")描述:其中第 0 个元素是整个模式匹配的结果,后面的三个元素依次为三个子组匹配的结果。 它们的下标分别为 1, 2, 3。

    经常我们会有一种需求需要使用子组进行分组,但又不需要(单独的)捕获它们。在子组定义的左括号后面紧跟字符串 ?: 会使得该子组不被单独捕获,并且不会对其后子组序号的计算产生影响。例如:

    字符串:"the red king"正则表达式:((?:red|white) (king|queen))匹配结果:array("red king", "red king", "king")

    为了方便简写,如果需要在非捕获子组开始位置设置选项, 选项字母可以位于 ? 和 : 之间,比如:

    (?i:saturday|sunday)(?:(?i)saturday|sunday)

    上記2つの書き方は実は同じパターンです。オプションの分岐は各分岐を左から右に試行し、サブモードの終了前にオプションはリセットされず、オプションの設定は後続の他の分岐に影響するため、上記のパターンは一致します。「日曜日」そして「土曜日」。

    IP アドレス ((2[0-4]d|25[0-5]|[01]?dd?) に一致する別の規則的なパターンを見てください。){3}(2[0-4]d|25[ 0-5]|[01]?dd?)
    関連記事 IP アドレスの正規表現

    結論

    上記には、PHP 正規表現で一般的に使用される文法が含まれています。次のような一部の文法は詳しく説明されていません。 、後方参照、アサーション、再帰パターンなど。これらは PHP マニュアルで確認できます。

    ヒント: 一般的に、同じ関数の場合、正規表現関数は文字列関数よりも効率的に実行されません。アプリケーションが単純な場合は、文字列式を使用します。ただし、単一の正規表現で実行できるタスクに複数の文字列関数を使用するのは間違いです。 ---- 書籍『PHP と MySQL で Web を開く』より抜粋。

    参考資料

    http://php.net/manual/zh/book.pcre.php
    https://msdn.microsoft.com/zh-cn/library/d9eze55x%28v=vs.80%29.
    http://deerchao.net/tutorials/regex/regex.htm
    http://tool.chinaz.com/regex/
    http://www.regexlab.com/zh/regref.htm

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。