ホームページ >バックエンド開発 >PHPチュートリアル >Php の正規表現の概要 (1)_PHP チュートリアル
1.コンセプト
構文パターンは に似ています。
区切り文字には、英数字、空白以外の任意の文字 (バックスラッシュ
式の中で区切り文字が使用されている場合は、バックスラッシュでエスケープする必要があります。
メタキャラクター
正規表現の基本コンポーネント
/アトムとメタキャラクター/パターン修飾子 /区切り文字を表す
正規表現の力は、パターン内に選択とループを含めることができることにあります。これらはメタキャラクタを使用してスキーマ内でエンコードされますが、メタキャラクタ自体は特別な方法で解析されません。
角括弧の内側か外側かで2種類に分かれます。
1. 角括弧の外側のメタ文字
メタキャラクター (シンボル) |
手順 |
通常、文字をエスケープするために使用されます |
|
^ |
ターゲットの開始位置(または複数行モードの場合は行の先頭)をアサートします |
$ |
ターゲットの終了位置 (複数行モードでは行の最後に存在します) |
. |
改行を除く任意の文字と一致します (デフォルト) |
[,] |
文字クラス定義の開始と終了 |
| |
オプションのブランチを開始する |
(、) |
サブグループの開始マーカーと終了マーカー |
? |
数量詞として、0 または 1 の一致を意味します。量指定子の後に配置され、量指定子の貪欲なプロパティを変更します |
* |
数量子、0 個以上の一致
|
+ |
数量指定子、1 つ以上の一致
|
{ ,} |
カスタマイズされた量指定子の開始タグ、終了タグ
|
2. パターン内の角括弧内の部分を「文字クラス」と呼びます
メタキャラクター |
手順 |
エスケープ文字 |
|
^ |
最初の文字として使用される場合のみ、文字クラスが反転されていることを示します |
- |
文字範囲をマークする |
メタキャラクターの使用例
1.エスケープ(バックスラッシュ)
の後に英数字以外の文字を続けると、その文字が持つ特別な意味が取り消されます。これは文字クラスの内外に当てはまります。
数字以外の文字の場合、元のテキストと照合するときに、それらがそれ自体を表していることを示すために、常にその文字の前にバックスラッシュを追加する必要があります。
「*」と一致する場合、特別な意味を持つため、特別な意味を解除するには「*」を使用してください
「.」と「.」を一致させる
「」と「\」を一致させます
ただし注意してください:
バックスラッシュは一重引用符で囲まれた文字列と二重引用符で囲まれた文字列で特別な意味を持ちます。そのため、バックスラッシュと一致させるには、パターンに「\\」または「\」を記述する必要があります
2. バックスラッシュの 2 番目の使用は、非印刷文字の表示エンコーディングを制御する手段を提供します。バイナリ
シンボル |
手順 |
あ |
ベル文字(16進数07)
|
cx |
「control-x」、x は任意の文字です
|
え |
エスケープ(ヘックス1B)
|
f |
ページ変更 (16 進数 0C)
|
ん |
改行(16進数0A)
|
p{xx} (p |
属性xxに一致する文字 |
P{xx} (p |
xx属性に一致しない文字 |
r |
Enter (16 進数 0D) を押します
|
ち |
水平タブ(16進数09)
|
くっ |
hh 16 進数でエンコードされた文字 |
ddd |
ddd 8 進数でエンコードされた文字、または後方参照
|
|
スペースの別の使用方法
|
40
|
提供されるサブグループが 40 未満の場合もスペースとみなされます。
|
7
|
常に後方参照
|
11
|
後方参照またはタブ文字の可能性があります
|
| 常にタブ
|
タブの後に 3 (毎回最大 3 つの 8 進数字しか読み取られないため) |
|
8進数の113で表される文字 |
|
377 |
8進数の377は10進数では255なので、すべて1の文字を表します
|
81 |
後方参照、または 2 進数の 0 とそれに続く 2 つの数値 8 と 1 (8 は有効な 8 進数ではないため)
|
3. 特定の文字クラスを記述するバックスラッシュの 3 番目の使用法
シンボル |
手順 |
d |
任意の 10 進数 |
D |
10 進数以外の任意の数値 |
は |
任意の水平方向の空白文字 |
H |
水平以外の空白文字 |
s |
任意の空白文字 |
S |
任意の空白文字 |
v |
任意の垂直空白文字 (PHP 5.2.4 以降)
|
V |
垂直以外の空白文字 (PHP 5.2.4 以降)
|
w |
任意の単語文字
|
W |
単語以外の文字
|
上記のエスケープ シーケンスの各ペアは、完全な文字セットの 2 つの互いに素な部分を表します。どの文字も、そのうちの 1 つに必ず一致しますが、もう 1 つは絶対に一致しません。
4 番目の使用法の単純なアサーション
b |
単語の境界 文字クラスではバックスペースであることに注意してください
|
B |
単語以外の境界
|
あ |
ターゲットの開始位置(複数行モードとは独立)
|
Z |
ターゲットの終了位置、または末尾の改行文字 (複数行モードとは独立)
|
z |
ターゲットの終了位置 (複数行モードとは独立)
|
G |
ターゲット内の最初の試合の位置
|
A、Z、Z
それらはターゲット文字列の先頭と末尾に常に一致し、パターン修飾子によって制限されないためです
Z と z の違いは、文字列の末尾文字が改行文字である場合、Z は文字列の末尾での一致と見なすのに対し、z は文字列の末尾のみと一致することです。
コード1
リーリーパターン修飾子 m
そしてコード
リーリー
m
追加後、
案の定、
同様に比較可能な
コード
リーリー
マッチング時にパターンがE
パターンを
$offset パラメータを指定した preg_match()() 呼び出しでは、現在のマッチング位置がマッチング開始点にある場合にのみ成功します
$offsetの値が0以外の場合はAとは異なります。
PHPマニュアルを参照
つまり、特別な意味を持つ文字をQとEの間に入れます
コード4など
リーリー
$ に一致します
PHP 5.2.4以降。 。たとえば、footKbar は「footbar」と一致します。しかし、得られたマッチング結果は「bar」です。ただし、K の使用はサブグループ内のコンテンツには影響しません。たとえば、(foot)Kbar が「footbar」と一致する場合、最初のサブグループの結果は依然として「foo」になります。翻訳者注: K をサブグループ内に配置した場合とサブグループ外に配置した場合の効果は同じです。
p{Lu} は大文字と一致します
期間キャラクタークラス
C はシングルバイトの一致に使用できます。つまり、UTF-8 モードではピリオドがマルチバイト文字に一致する可能性があります
|
|
文字と数字 |
|
手紙 |
|
0 - 127 の ASCII 文字 |
|
スペースと水平タブ |
|
コントロールキャラクター |
|
10進数(dと同じ) |
|
スペースを除いた文字を印刷します |
|
小文字 |
|
スペースを含む文字を印刷します |
|
文字と数字を除く文字を印刷します |
|
空白文字 (s よりも垂直タブが多い) |
|
アッパー |
大文字 |
言葉 |
単語文字(wと同じ) |
x桁 |
16 進数 |
比如'#[[:upper:]]#'匹配大写字母
'#[[:alpha:]]#' 匹配字母
竖线字符用于分离模式中的可选路径。 比如模式gilbert|Sullivan匹配 ”gilbert” 或者 ”sullivan”。 竖线可以在模式中出现任意多个,并且允许有空的可选路径(匹配空字符串)。 匹配的处理从左到右尝试每一个可选路径,并且使用第一个成功匹配的。 如果可选路径在子组(下面定义)中, 则”成功匹配”表示同时匹配了子模式中的分支以及主模式中的其他部分。
代码5
<span $p</span>='#p(hp|ython|erl)#'<span ; </span><span $str</span>="php python perl"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $all</span><span ); </span><span print_r</span>(<span $all</span>);
子组通过圆括号分割界定,并且它们可以嵌套,主要有以下两种用法与功能
1.将可选分支局部化。比如
模式 p(hp|ython|erl) 匹配
2.将子组设定为捕获子组。
整个模式匹配后, 左括号从左至右出现的次序就是对应子组的下标(从 1 开始), 可以通过这些下标数字来获取捕获子模式匹配结果。
代码6
<span $p</span>='#(\d)#'<span ; </span><span $str</span>="abc123"<span ; </span><span $r</span>=<span preg_replace</span>(<span $p</span>,'<font color=red>\1</font>',<span $str</span><span ); </span><span echo</span> <span $r</span>;
在子组定义的左括号后面紧跟字符串 ”?:” 会使得该子组不被单独捕获, 并且不会对其后子组序号的计算产生影响
代码7:匹配数字 把数字改为红色的
<span $p</span>='#.*(?:\d).*([a-z])#U'<span ; </span><span $str</span>="3df5g"<span ; </span><span $r</span>=<span preg_replace</span>(<span $p</span>,'<font color=red>\1</font>',<span $str</span><span ); </span><span echo</span> <span $r</span>;
如果匹配数字的模式不加?:
那么
为了方便简写,如果需要在非捕获子组开始位置设置选项, ,比如:
上面两种写法实际上是相同的模式。因为可选分支会从左到右尝试每个分支, 并且选项没有在子模式结束前被重置, 并且由于选项的设置会穿透对后面的其他分支产生影响,因此, 上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。
在 PHP 4.3.3 中,
代码如下8:
<span $p</span>="#.*(?<alpha>[a-z]{3})(?'digit'\d{3}).*#"<span ; </span><span $str</span>="abc123111def111g"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果:
有时需要多个匹配可以在一个正则表达式中选用子组。 为了让多个子组可以共用一个后向引用数字的问题, (?\语法允许复制数字。 考虑下面的正则表达式匹配Sunday:
(?:(Sat)ur|(Sun))day
这里当后向引用 1 空时Sun 存储在后向引用 2 中. 当后向引用 2 不存在的时候 Sat 存储在后向引用 1中。 使用 (?|修改模式来修复这个问题:
代码9:
<span $p</span>='#(?:(sat)ur|(sun))day#'<span ; </span><span $str</span>="sunday saturday"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果:
(?|(Sat)ur|(Sun))day
使用这个模式, Sun和Sat都会被存储到后向引用1中。
在看这个模式前先看以2个下代码
代码10-1
$p=<span '</span><span #(a|b)\d#</span><span '</span><span ; $str</span>=<span "</span><span b2a1</span><span "</span><span ; preg_match_all($p,$str,$arr); print_r($arr);</span>
结果是:Array
<em id="__mceDel">( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ) )<br /><span <strong>代码10-2</strong></span><br /></em>
$p=<span '</span><span #((a)|b)\d#</span><span '</span><span ; $str</span>=<span "</span><span b2a1</span><span "</span><span ; preg_match_all($p,$str,$arr); print_r($arr);</span>
结果:
<strong>Array ( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ) [2] => Array ( [0] => [1] => a )</strong> )<br /><strong>对10-2代码:<br /></strong>第一次完整匹配到的内容是b2,所以包括匹配内容b的括号即为其第一个子模式是即为b,第二个子模式由于(a)没有匹配,所以为空<br />第二次完整匹配到a1,其第一个子模式为a,第二次的由于((a)|b)是外层大括号里包含的<br /><strong>代码10-3:<br /></strong>
$p=<span '</span><span #((a)|(b))\d#</span><span '</span><span ; $str</span>=<span "</span><span b2a1</span><span "</span><span ; preg_match_all($p,$str,$arr); print_r($arr);</span>
<strong> 结果:<br /></strong>
Array ( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ) [2] => Array ( [0] => [1] => a ) [3] => Array ( [0] => b [1] => ) )
代码10-4:
$p=<span '</span><span #(?:(a)|(b))\d#</span><span '</span><span ; $str</span>=<span "</span><span b2a1</span><span "</span><span ; preg_match_all($p,$str,$arr); print_r($arr);</span>
结果:<br />Array ( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => [1] => a ) [2] => Array ( [0] => b [1] => ) )
<strong> </strong>
代码10:
<span $p</span>='#(?|(sat)ur|(sun))day#'<span ; </span><span $str</span>="sunday saturday"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果
如果紧跟反斜线的数字小于 10, 它总是一个后向引用。模式中的捕获数要大于等于后向引用的个数
后向引用会直接匹配被引用捕获组在目标字符串中实际捕获到的内容, 而不是匹配子组模式的内容
(sens|respons)e and \1ibility将会匹配
<span $p</span>='#(sens|respons)e and \1ibility#'<span ; </span><span $str</span>="sense and sensibility response and responsibility sense and responsibility"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果
ab(?i)c匹配abC
如果在后向引用时被强制进行了大小写敏感匹配
((?i)abc)\s+\1
匹配
ABC ABC
AbC AbC
只要两个一样不分大小写
但不匹配
这里其实要考虑的是后向引用期望得到的内容是和那个被引用的捕获子组得到的内容是完全一致的
代码12:
<span $p</span>='#((?i)abc)\s+\1#'<span ; </span><span $str</span>="abc abc |ABC ABC |AbC AbC |abc Abc "<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果
先看以下代码13
<span $p</span>='#(a|(bc))#'<span ; </span><span $str</span>="abc "<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
完整匹配了2次
[0][0]是第一次完整的匹配
[1][0]是第一次匹配的第一个子模式
[2][0]是第一次匹配的第二个子模式
[0][1]第二次完整匹配
[1][1]第二次匹配的第一个子模式
[2][1]是第二次匹配的第二个子模式
从上面可以发现对于模式
(a|(bc))
最外面的括号是第一个匹配子模式
里面的括号里的是第二个子模式
所以对于以下代码14:
<span $p</span>='#(a|(bc))\2#'<span ; </span><span $str</span>="aabcbc"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果
当第一匹配
就无从
所以第一次完整匹配中必须得有让第二个子模式存在的机会即里面的括号里的内容必须被匹配到,所以必须得有
因为可能会有多达 99 个后向引用, 所有紧跟反斜线后的数字都可能是一个潜在的后向引用计数。 如果模式在后向引用之后紧接着还是一个数值字符, 那么必须使用一些分隔符用于终结后向引用语法。
以下代码15为例:
<span $p</span>='#([a-z]{3})\1 5#x'<span ; </span><span $str</span>="aaaaaa5"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
模式后向引用\1
我们空下一格,然后在模式修正里忽略模式里的空格就能成功匹配
(a\1) 就不会得到任何匹配
而这种引用可以用于内部的子模式重复
(a|b\1)会匹配 ”a”但不会匹配b( 因为子组内部有一个可选路径,可选路径中有一条路能够完成匹配,在匹配完成后, 后向引用就能够引用到内容了)。
代码16:
<span $p</span>='#(a|b\1)+#'<span ; </span><span $str</span>="abba"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果
在每次子模式的迭代过程中, 后向引用匹配上一次迭代时这个子组匹配到的字符串。为了做这种工作, 模式必须满足这样一个条件,模式在第一次迭代的时候, 必须能够保证不需要匹配后向引用。 这种条件可以像上面的例子用可选路径来实现,也可以通过使用最小值为 0 的量词修饰后向引用的方式来完成。
在 PHP 5.2.2之后, g转义序列可以用于子模式的绝对和相对引用。 这个转义序列必须紧跟一个无符号数字或一个负数, 可以选择性的使用括号对数字进行包裹。 序列\1, \g1,\g{1} 之间是同义词关系。 这种用法可以消除使用反斜线紧跟数值描述反向引用时候产生的歧义。 这种转义序列有利于区分后向引用和八进制数字字符, 也使得后向引用后面紧跟一个原文匹配数字变的更明了,比如 \g{2}1。
代码17:
<span $p</span>='#([a-z]{2})\g{1}5#'<span ; </span><span $str</span>="abab5"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
可与代码15对比
\g 转义序列紧跟一个负数代表一个相对的后向引用。比如: (foo)(bar)\g{-1} 可以匹配字符串 ”foobarbar”(foo)(bar)\g{-2} 可以匹配 ”foobarfoo”。 这在长的模式中作为一个可选方案, 用来保持对之前一个特定子组的引用的子组序号的追踪。
代码18
<span $p</span>='#(foo)(bar)\g{-1}#'<span ; </span><span $p1</span>='#(foo)(bar)\g{-2}#'<span ; </span><span $str</span>="foobarbar"<span ; </span><span $str1</span>="foobarfoo"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span preg_match_all</span>(<span $p1</span>,<span $str1</span>,<span $arr1</span><span ); </span><span print_r</span>(<span $arr</span><span ); </span><span print_r</span>(<span $arr1</span>);
结果:
后向引用也支持使用子组名称的语法方式描述, 比如 (?P=name) 或者 PHP 5.2.2 开始可以实用\k8a11bc632ea32a57b3e3693c7987c420 或 \k’name’。 另外在 PHP 5.2.4 中加入了对\k{name} 和 \g{name} 的支持。
代码19:
<span $p</span>="#(?<span 'alpha'</span>[a-z]{2})(?<digt>[0-9]{3})\k<digt>(?<span P=alpha</span>)#"<span ; </span><span $str</span>="aa123123aa"<span ; </span><span preg_match_all</span>(<span $p</span>,<span $str</span>,<span $arr</span><span ); </span><span print_r</span>(<span $arr</span>);
结果:
可与代码8比较着看
注意标红的
Alpha
P