コンピューターでは、必要なファイルを見つけるために (ワイルドカード) 文字をよく使用します。例えば: *.doc
,这里的 *
は 0 個以上の文字と一致することを意味します。正規表現もテキストの一致に使用されるツールですが、より強力です。 PHP マニュアルから文を引用すると、次のようになります。 正規表現は、ターゲット文字列に左から右に一致するパターンです。ほとんどの文字は、それ自体に一致するパターンを表します。
正規表現を予備的に理解するために、いくつかの簡単な例を以下に示します。
リーリー リーリー リーリー リーリー上記の例の b
, .
, *
, d
, {2}
はすべて特別な意味を持っており、それについては以下で説明します。
PHP では、POSIX と PCRE の 2 種類の正規表現がサポートされています。 PHP 5.3.0 以降、POSIX 正規表現拡張機能は非推奨になりました。したがって、以下の説明は PCRE モードに基づいています。クリックすると、POSIX 正規表現との違いおよび Perl との違いが表示されます。
PCRE関数を使用する場合、パターンをデリミタで囲む必要があります。区切り文字には、英数字、バックスラッシュ、または空白文字以外の任意の文字を使用できます。頻繁に使用される区切り文字はスラッシュ /
、hash符号 #
以及取反符号 ~
です。次の例はすべて、正当な区切り文字を使用したパターンです。
パターン内で区切り文字を一致させる必要がある場合は、バックスラッシュでエスケープする必要があります。パターン内で区切り文字が頻繁に発生する場合は、読みやすさを向上させるために他の区切り文字を使用することをお勧めします。例:
リーリー 正規表現の威力は、パターン内で選択して繰り返す機能から生まれます。一部の文字には特別な意味が与えられており、それ自体を単に表すのではなく、パターン内で特別な意味を持つエンコードされた文字は メタ文字 と呼ばれます。
2 つの異なるメタ文字があります。1 つは角括弧の外側のパターン内のどこでも使用できるもので、もう 1 つは角括弧の内側で使用する必要があります。
角括弧の外側で使用されるメタ文字は次のとおりです:
コード | 手順 |
---|---|
/ | 通常、文字をエスケープするために使用されます |
^ | ターゲットの開始位置(または複数行モードの場合は行の先頭)をアサートします |
$ | ターゲットの終了位置(または複数行モードの行末)をアサートします |
. | 改行を除く任意の文字と一致します (デフォルト) |
[ | 文字クラス定義の開始 |
] | 文字クラス定義の終了 |
| | オプションのブランチを開始する |
( | サブグループの開始タグ |
) | サブグループの終了タグ |
? | a: 量指定子として、0 または 1 の一致を示します。 b: 量指定子の後に位置し、量指定子の貪欲な特性を変更するために使用されます。 |
* | 数量子、0 個以上の一致 |
+ | 数量指定子、1 つ以上の一致 |
{ | カスタマイズされた量指定子の開始タグ |
} | カスタマイズされた量指定子終了タグ |
パターン内の角括弧内の部分を「文字クラス」と呼びます。 文字クラス内で使用できるメタ文字は次のとおりです:
コード | 手順 |
---|---|
エスケープ文字 | |
^ | 最初の文字 (角括弧内) として使用される場合のみ、文字クラスが反転されていることを示します |
- | 文字範囲をマークする |
例:
baw*b
文字 a で始まる単語、最初に単語の先頭の b、次に文字 a、その後に任意の数の任意の単語文字と一致します (単語文字とは任意の文字、数字、アンダースコアを指します) w*、および最後に単語の終わりです b。 d+
1 つ以上の連続する数字と一致します。 ^d{5,12}$
5 ~ 12 桁に一致します。 ^ と $ が使用されるため、入力文字列全体を d{5,12} に一致させる必要があります。つまり、入力全体が 5 ~ 12 桁である必要があります。 バックスラッシュ には 4 つの用途があります。詳細については、エスケープ シーケンス (バックスラッシュ)
と一致させたい場合は、エスケープ文字として *
字符,就需要在模式中写为 *
。这适用于一个字符在不进行转义会有特殊含义的情况下。 但是,对于非数字字母的字符,总是在需要其进行原文匹配的时候在它前面增加一个反斜线,来声明它代表自己,这是安全的。如果要匹配一个反斜线,那么在模式中使用 \
[1] を使用します。
バックスラッシュは一重引用符で囲まれた文字列と二重引用符で囲まれた文字列の両方で特別な意味を持っているため、バックスラッシュと一致させるには、パターンを \
として記述する必要があります。理由は、まず文字列として使用され、バックスラッシュがエスケープされるからです。最後に、正規表現エンジンはバックスラッシュもエスケープされるとみなします。したがって、1 つのバックスラッシュと一致するには 4 つのバックスラッシュが必要です。
[2] 非印刷文字の表示エンコーディングの制御メソッドを提供します
【3】特定の文字クラスを説明するために使用されます
コード | 手順 |
---|---|
d | 任意の 10 進数 |
D | 10 進数以外の任意の数値 |
え | 水平方向の空白文字 (PHP 5.2.4 以降) |
ひ | 水平以外の空白文字 (PHP 5.2.4 以降) |
す | 任意の空白文字 |
S | 空白以外の文字 |
v | 任意の垂直空白文字 (PHP 5.2.4 以降) |
V | 垂直以外の空白文字 (PHP 5.2.4 以降) |
w | Word の文字とは、任意の文字、数字、アンダースコアを指します。 |
わ | 単語以外の文字 |
【4】いくつかの簡単な主張。アサーションは、特定の位置で一致する必要がある条件を指定します。ターゲット文字列の文字は消費されません。バックスラッシュ アサーションには次のものが含まれます:
b
単語の境界B
単語以外の境界A
ターゲットの開始位置 (複数行モードとは独立) Z
ターゲットの終了位置、または末尾の改行文字 (複数行モードとは独立) z
ターゲットの終了位置 (複数行モードとは独立) G
ターゲット内の最初の試合の位置 コード | 手順 |
---|---|
* | ゼロ回以上繰り返され、 | と同等
+ | 1 回以上繰り返され、 | と同等
? | 0 回または 1 回繰り返します ( | と同等)
{n} | n回繰り返します |
{n,} | n回以上繰り返す |
{n,m} | n回からm回繰り返します |
默认情况下,量词都是”贪婪”的,也就是说,它们会在不导致模式匹配失败的前提下,尽可能多的匹配字符(直到最大允许的匹配次数)。然而,如果一个量词紧跟着一个 ?
标记,它就会成为懒惰(非贪婪)模式, 它不再尽可能多的匹配,而是尽可能少的匹配。
下面直接看示例,理解“贪婪”和“非贪婪”模式是怎么回事。
对于字符串 "aa<span class="nt"><div></span>test1<span class="nt"></div></span>bb<span class="nt"><div></span>test2<span class="nt"></div></span>cc" 正则表达式 "<span class="nt"><div></span>.*<span class="nt"></div></span>" 匹配结果 "<span class="nt"><div></span>test1<span class="nt"></div></span>bb<span class="nt"><div></span>test2<span class="nt"></div></span>" 正则表达式 "<span class="nt"><div></span>.*?<span class="nt"></div></span>" 匹配结果 "<span class="nt"><div></span>test1<span class="nt"></div></span>"
关于更多“贪婪”和“非贪婪”模式的介绍可查阅 http://php.net/manual/zh/regexp.reference.repetition.php
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}
。
竖线字符用于分离模式中的可选路径。比如模式 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 位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。
使用分枝条件时,要注意各个条件的顺序
正则表达式在不同的模式修饰符下匹配出的结果有可能不相同。它的语法是 :(?修饰符)
比如,(?im)
设置表明多行大小写不敏感匹配。同样可以用它来取消这些设置,比如 (?im-sx)
设置了 “PCRE_CASELESS”,”PCRE_MULTILINE”,但是同时取消了 “PCRE_DOTALL” 和 “PCRE_EXTENDED”。如果一个字母即出现在 -
之前, 也出现在 -
之后,这个选项被取消设置。
下面紧例举简单的示例,想要了解更多可点击 内部选项设置 和 模式修饰符
示例:/ab(?i)c/
仅仅匹配 ”abc” 和 ”abC”
子组通过圆括号分隔界定,并且它们可以嵌套。
示例:
字符串:"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)
上面两种写法实际上是相同的模式。因为可选分支会从左到右尝试每个分支,并且选项没有在子模式结束前被重置,并且由于选项的设置会穿透对后面的其他分支产生影响,因此, 上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。
再看一个匹配 IP 地址的正则 ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
相关文章 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.aspx
http://deerchao.net/tutorials/regex/regex.htm
http://tool.chinaz.com/regex/
http://www.regexlab.com/zh/regref.htm