Php の正規表現のまとめ (1)

WBOY
リリース: 2016-06-23 14:36:56
オリジナル
871 人が閲覧しました

1. 概念

構文パターンは、スラッシュ (/) などの区切り記号で閉じる必要があります。バックスラッシュ () とスペース バイト外の非空白文字 ASCII 文字

式の中で区切り文字が使用されている場合は、バックスラッシュでエスケープする必要があります。

2. 構成

メタキャラクター

正規表現の基本的な構成

/アトムとメタキャラクター/パターン修飾子 パターンには選択とループが含まれます。これらはメタキャラクタを使用してスキーマ内でエンコードされますが、メタキャラクタ自体は特別な方法で解析されません。

角括弧の内側か外側かで2種類に分かれます。 ...

^

として量指定子。0 回または 1 回の一致を意味します。量指定子の貪欲なプロパティを変更するために量指定子の後に使用します + 、1 つ以上の一致 カスタム量指定子の開始タグ、終了タグ エスケープ文字^
ターゲットの開始位置 (または複数行モードの行の先頭) をアサート

$
の終了位置target (複数行モードでは行末に存在します)

.
改行を除く任意の文字と一致します (デフォルト)

[,]
始まり、終わり文字クラス定義

|
オプションの分岐を開始

(,)
サブグループの開始マークと終了マーク

?

*

量指定子、0 個以上の一致

{ ,}

2. パターン内の角括弧 内側の部分を「文字クラス」と呼びます

メタキャラクター

説明

最初の文字として使用される場合のみ、否定を示しますキャラクタークラスの

メタキャラクターの使用手順の例

1. エスケープ (バックスラッシュ)

に英数字以外の文字を続けると、その文字が持つ特別な意味が取り消されます。これは文字クラスの内外に当てはまります。

数字以外の文字の場合は、元のテキストと照合するときに、それらがそれ自体を表していることを示すために、常にその文字の前にバックスラッシュを追加する必要があります。

「*」と一致する場合、特別な意味があるため、「*」を使用してその特別な意味を解除します

「.」と「.」を一致させます

「"」と「\」を一致させます

ただし、次のことに注意してください:

バックスラッシュは一重引用符で囲まれた文字列と二重引用符で囲まれた文字列で特別な意味を持ちます。そのため、バックスラッシュと一致させるには、パターン内に「\\」または「\」を記述する必要があります。

2 番目のスラッシュの使用は、非印刷文字の表示エンコーディングを制御する手段。非印刷文字 (それ自体) の出現については、バイナリ 0 でパターンが終了することを除いて、厳密な制限はありません。ただし、テキスト エディタを使用してパターンを作成する場合は、バイナリ文字を使用するよりも次のエスケープ シーケンスを使用する方が適切です。もっと簡単に。

-

文字範囲をマーク

シンボル

説明

a

07)

cx

" control-x "、x は任意の文字です

e

escape (hex 1B)

f

ページ変更 (16 進数システム 0C)

n

改行 (16 進数 0A)

p{xx} (p small Write)

xx 属性に一致する文字

P{xx } (p大文字)

xx属性に一致しない文字

r

Enter (hex) Made 0D)

t

水平タブ文字 (16 進数 09)

xhh

hh 16 進数でエンコードされた文字

ddd

ddd 8 進数でエンコードされた文字、または後方参照

上記のエスケープ シーケンスの各ペアは、完全な文字セットの 2 つの互いに素な部分を表しており、どの文字もそのうちの 1 つに必ず一致しますが、もう 1 つは絶対に一致しません。

4 番目の使用法 単純なアサーション

b

単語境界 文字クラスではバックスペースであることに注意してください

B

非単語境界

A

ターゲットの開始位置 (複数行モードとは独立)

Z

またはターゲットの改行の終わり (複数行とは独立)モード )

z

ターゲットの終了位置 (複数行モードとは独立)

G

ターゲットでの最初の試合の位置

A,Z,z アサーションは、従来の ^ や $

とは異なります。なぜなら、それらは常にターゲット文字列の先頭と末尾に一致し、パターン修飾子によって制限されないからです。

Z と理由は、文字列の末尾文字が改行文字の場合、Z は文字列の末尾での一致とみなし、z は文字列の末尾のみと一致するためです。

コード 1

$p='#\A[a-z]{3}#m';$str='abcdefghijkl';preg_match_all($p,$str,$all);print_r($all);
ログイン後にコピー

パターン修飾子 m が追加されているかどうかに関係なく、結果は同じです

abc のみに一致します

コード 2:

$p='#^[a-z]{3}#m';$str='abcdefghijkl';preg_match_all($p,$str,$all);print_r($all);
ログイン後にコピー

m なしでは、のみが一致しますabc

追加後、abc、def、hij は一致します

案の定、A はパターン修飾子の影響を受けません

$ と Z

Z と z

コード 3

rreええ

モードをEに修正すると、a

と一致します

モードをeに修正すると、文字の末尾のみに一致し、改行文字を認識しないため、何も一致しません

G アサーションは $ の後に指定します offset パラメータの preg_match()() 呼び出しでは、現在のマッチング位置がマッチング開始点の場合のみ成功します

$offset の値が 0 以外の場合は、 Aとは異なります。

PHP マニュアルを参照してください

PHP 4.3.3 以降、Q と E を使用してパターン内の正規表現メタ文字を無視できます

つまり、Q と E の間に特別な意味を持つ文字を入れます。コード 4 の

$p='#[a-z]\Z#'; $str="a\n"; preg_match_all($p,$str,$all); print_r($all);
ログイン後にコピー

は、PHP 5.2.4 以降の a.$.

に一致します。 K を使用してマッチングをリセットできます。たとえば、footKbar は「footbar」と一致します。しかし、得られたマッチング結果は「bar」です。ただし、K の使用はサブグループ内のコンテンツには影響しません。たとえば、(foot)Kbar が「footbar」と一致する場合、最初のサブグループの結果は依然として「foo」になります。翻訳者注: K をサブグループ内に配置した場合とサブグループ外に配置した場合の効果は同じです。

p{Lu} は大文字と一致します

ピリオド

文字クラスの外では

C を使用してシングルバイトと一致できます。つまり、UTF-8 モードではピリオドはマルチバイト文字と一致します

punctスペース上単語xdigit

文字クラス

alnum

文字と数字

alpha

文字

ascii

0 - 127 の ASCII 文字

空白

スペースと水平タブ

cntrl

制御文字

数字

10進数(dと同じ)

グラフ

スペースを除く文字を印刷

小文字

小文字

スペースを含む文字を印刷

印刷文字、除く文字と数字

空白文字(sよりも垂直タブ)

大文字

単語文字 ( wと同じ)

16進数

比如'#[[:upper:]]#'匹配大写字母

'#[[:alpha:]]#' 匹配字母

可选路径|

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

代码5

$p='#p(hp|ython|erl)#';$str="php python perl";preg_match_all($p,$str,$all);print_r($all);
ログイン後にコピー

子组(子模式)

子组通过圆括号分割界定,并且它们可以嵌套,主要有以下两种用法与功能

1.将可选分支局部化。比如

模式 p(hp|ython|erl) 匹配php,python,perl中的一个

2.将子组设定为捕获子组。

整个模式匹配后, 左括号从左至右出现的次序就是对应子组的下标(从 1 开始), 可以通过这些下标数字来获取捕获子模式匹配结果。

代码6

$p='#(\d)#';$str="abc123";$r=preg_replace($p,'<font color=red>\1</font>',$str);echo $r;
ログイン後にコピー

但当只想分组而又不想捕获时

在子组定义的左括号后面紧跟字符串 ”?:” 会使得该子组不被单独捕获, 并且不会对其后子组序号的计算产生影响

代码7:匹配数字 把数字改为红色的

$p='#.*(?:\d).*([a-z])#U';$str="3df5g";$r=preg_replace($p,'<font color=red>\1</font>',$str);echo $r;
ログイン後にコピー

如果匹配数字的模式不加?:

那么\1代表的就是匹配就是数字,加上后只是分组不捕获了,\1就代表捕获的字母了

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

(?i:saturday|Sunday)

(?:(?i)saturday|Sunday)

其中i是模式修正符,忽略大小写

上面两种写法实际上是相同的模式。因为可选分支会从左到右尝试每个分支, 并且选项没有在子模式结束前被重置, 并且由于选项的设置会穿透对后面的其他分支产生影响,因此, 上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。

在 PHP 4.3.3 中,可以对子组使用 (?Ppattern) 的语法进行命名。 这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现, PHP 5.2.2中又增加了两种味子组命名的语法: (?pattern) 和 (?’name’pattern)。

代码如下8:

$p="#.*(?<alpha>[a-z]{3})(?'digit'\d{3}).*#";$str="abc123111def111g";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果:

有时需要多个匹配可以在一个正则表达式中选用子组。 为了让多个子组可以共用一个后向引用数字的问题, (?\语法允许复制数字。 考虑下面的正则表达式匹配Sunday:

(?:(Sat)ur|(Sun))day

这里当后向引用 1 空时Sun 存储在后向引用 2 中. 当后向引用 2 不存在的时候 Sat 存储在后向引用 1中。 使用 (?|修改模式来修复这个问题:

代码9:

$p='#(?:(sat)ur|(sun))day#';$str="sunday saturday";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果:

(?|(Sat)ur|(Sun))day

使用这个模式, Sun和Sat都会被存储到后向引用1中。

在看这个模式前先看以2个下代码

代码10-1

$p='#(a|b)\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果是:Array

(    [0] => Array        (            [0] => b2            [1] => a1        )    [1] => Array        (            [0] => b            [1] => a        ))代码10-2
ログイン後にコピー

$p='#((a)|b)\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果:

Array(    [0] => Array        (            [0] => b2            [1] => a1        )    [1] => Array        (            [0] => b            [1] => a        )    [2] => Array        (            [0] =>             [1] => a        ))对10-2代码:第一次完整匹配到的内容是b2,所以包括匹配内容b的括号即为其第一个子模式是即为b,第二个子模式由于(a)没有匹配,所以为空第二次完整匹配到a1,其第一个子模式为a,第二次的由于((a)|b)是外层大括号里包含的代码10-3:
ログイン後にコピー

$p='#((a)|(b))\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

 结果:
ログイン後にコピー
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='#(?:(a)|(b))\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果:Array(    [0] => Array        (            [0] => b2            [1] => a1        )    [1] => Array        (            [0] =>             [1] => a        )    [2] => Array        (            [0] => b            [1] =>         ))
ログイン後にコピー

 
ログイン後にコピー

代码10:

$p='#(?|(sat)ur|(sun))day#';$str="sunday saturday";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果

后向引用

如果紧跟反斜线的数字小于 10, 它总是一个后向引用。模式中的捕获数要大于等于后向引用的个数

后向引用会直接匹配被引用捕获组在目标字符串中实际捕获到的内容, 而不是匹配子组模式的内容

(sens|respons)e and \1ibility将会匹配 ”sense and sensibility” 和 ”response and responsibility”, 而不会匹配 ”sense and responsibility”。

代码11

$p='#(sens|respons)e and \1ibility#';$str="sense and sensibility response and responsibility  sense and responsibility";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果

ab(?i)c匹配abC和abc

(?i)+原子

表示(?i)后的原子不区分大小写

如果在后向引用时被强制进行了大小写敏感匹配

((?i)abc)\s+\1

匹配 abc abc

ABC ABC

AbC AbC

只要两个一样不分大小写

但不匹配 ABC aBC等

这里其实要考虑的是后向引用期望得到的内容是和那个被引用的捕获子组得到的内容是完全一致的

代码12:

$p='#((?i)abc)\s+\1#';$str="abc abc |ABC ABC  |AbC AbC |abc Abc ";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果

可能会有超过一个的后向引用引用相同的子组。 一个子组可能并不会真正的用于特定的匹配,此时, 任何对这个子组的后向引用也都会失败。

先看以下代码13

$p='#(a|(bc))#';$str="abc ";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

完整匹配了2次

[0][0]是第一次完整的匹配

[1][0]是第一次匹配的第一个子模式

[2][0]是第一次匹配的第二个子模式

[0][1]第二次完整匹配

[1][1]第二次匹配的第一个子模式

[2][1]是第二次匹配的第二个子模式

从上面可以发现对于模式

(a|(bc))

最外面的括号是第一个匹配子模式

里面的括号里的是第二个子模式

所以对于以下代码14:

$p='#(a|(bc))\2#';$str="aabcbc";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果

当第一匹配a时,就没有第二子模式了

就无从\2谈起

所以第一次完整匹配中必须得有让第二个子模式存在的机会即里面的括号里的内容必须被匹配到,所以必须得有bc才能有匹配。

因为可能会有多达 99 个后向引用, 所有紧跟反斜线后的数字都可能是一个潜在的后向引用计数。 如果模式在后向引用之后紧接着还是一个数值字符, 那么必须使用一些分隔符用于终结后向引用语法。

以下代码15为例:

$p='#([a-z]{3})\1 5#x';$str="aaaaaa5";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

模式后向引用\1后紧跟数字的话就像以上代码 就会误认为第15个引用

我们空下一格,然后在模式修正里忽略模式里的空格就能成功匹配

如果一个后向引用出现在它所引用的子组内部, 它的匹配就会失败

(a\1) 就不会得到任何匹配

而这种引用可以用于内部的子模式重复

(a|b\1)会匹配 ”a”但不会匹配b( 因为子组内部有一个可选路径,可选路径中有一条路能够完成匹配,在匹配完成后, 后向引用就能够引用到内容了)。

代码16:

$p='#(a|b\1)+#';$str="abba";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果

在每次子模式的迭代过程中, 后向引用匹配上一次迭代时这个子组匹配到的字符串。为了做这种工作, 模式必须满足这样一个条件,模式在第一次迭代的时候, 必须能够保证不需要匹配后向引用。 这种条件可以像上面的例子用可选路径来实现,也可以通过使用最小值为 0 的量词修饰后向引用的方式来完成。

在 PHP 5.2.2之后, \g转义序列可以用于子模式的绝对和相对引用。 这个转义序列必须紧跟一个无符号数字或一个负数, 可以选择性的使用括号对数字进行包裹。 序列\1, \g1,\g{1} 之间是同义词关系。 这种用法可以消除使用反斜线紧跟数值描述反向引用时候产生的歧义。 这种转义序列有利于区分后向引用和八进制数字字符, 也使得后向引用后面紧跟一个原文匹配数字变的更明了,比如 \g{2}1。

代码17:

$p='#([a-z]{2})\g{1}5#';$str="abab5";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

可与代码15对比

\g 转义序列紧跟一个负数代表一个相对的后向引用。比如: (foo)(bar)\g{-1} 可以匹配字符串 ”foobarbar”, (foo)(bar)\g{-2} 可以匹配 ”foobarfoo”。 这在长的模式中作为一个可选方案, 用来保持对之前一个特定子组的引用的子组序号的追踪。

代码18

$p='#(foo)(bar)\g{-1}#';$p1='#(foo)(bar)\g{-2}#';$str="foobarbar";$str1="foobarfoo";preg_match_all($p,$str,$arr);preg_match_all($p1,$str1,$arr1);print_r($arr);print_r($arr1);
ログイン後にコピー

结果:

后向引用也支持使用子组名称的语法方式描述, 比如 (?P=name) 或者 PHP 5.2.2 开始可以实用\k 或 \k’name’。 另外在 PHP 5.2.4 中加入了对\k{name} 和 \g{name} 的支持。

代码19:

$p="#(?'alpha'[a-z]{2})(?<digt>[0-9]{3})\k<digt>(?P=alpha)#";$str="aa123123aa";preg_match_all($p,$str,$arr);print_r($arr);
ログイン後にコピー

结果:

可与代码8比较着看

注意标红的

Alpha前一个有引号,后一个没有

P大写

参考资料:

未完待续....

 

 

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート