精品一区二区三区影院在线午夜_天天躁日日躁狠狠躁AV麻豆_国产午夜福利短视频_中文字幕乱偷无码AV先锋蜜桃_久久精品一二区东京热_国产成人亚洲日韩欧美久久久,国产成人精品久久一区二区三区

正則表達式之二:與正則表達式進(jìn)行匹配-正則表達式與Perl接軌

1、以m//進(jìn)行匹配

//的編寫(xiě)模式是m//操作符的簡(jiǎn)寫(xiě)。

例:m(fred)=m<fred>=m{fred}=m[fred]=m/fred/=/fred/

批注:但只有//可以省略m。

例:/^http:\/\//=m%^http://%

批注:匹配http://,常見(jiàn)的定界符也有用花括號的

2、可選修飾符

可有可無(wú)的修飾字符,有時(shí)候稱(chēng)為開(kāi)關(guān)。它們可以成組附加在某個(gè)正則表達式結尾的定界符的右邊,并改變正則表達式的默認行為。

一個(gè)模式里使用多個(gè)修飾符,可以寫(xiě)在一起,不分先后順序。

/i:不區分大小寫(xiě)的匹配

例:/yes/i

批注:匹配Yes,yes,YES等等

/s:匹配任意字符,如點(diǎn)號(.)不匹配換行符,但加上/s后效果等于[\d\D]

/x:加入空白,在模式里隨意加上空白,使更容易閱讀、理解。

例:/-?\d\.?\d*/=/-? \d \.? \d* /x

例:/barney.*fred/is = /barney .* fred/isx

批注:這樣加入空白后,閱讀更清楚些。但加上/s后模式里面原始的空白與制表符就失去意義,它們會(huì )被忽略掉,如果想要匹配的話(huà),可以在前面加上反斜線(xiàn)轉義符\,不過(guò)\s(或\s*、或\s+)還是比較常用的用來(lái)匹配空白的寫(xiě)法。若要匹配#時(shí),可以寫(xiě)成\#或[#]。另注釋里不要把定界符也寫(xiě)進(jìn)去,不然會(huì )被視為模式的終點(diǎn)。

3、定位

(1)字符匹配的定位

^用來(lái)標識字符串的開(kāi)頭

例:/^fred/ #只匹配位于字符串最前端的fred,如果是manfred mann這個(gè)字符串,則不匹配

$用來(lái)標識字符串的結尾

例:/rock$/

批注:只匹配位于字符串最后面的rock,如果是knute rockne,則不匹配

例:/^(fred|barney)/

批注:其中的括號很重要,現在的意思是在每行開(kāi)頭尋找fred或barney,若沒(méi)有圓括號,就會(huì )變成在字符串的開(kāi)頭匹配fred或者在字符串的任何地方匹配barney。

兩個(gè)字符定位一起使用,可確保模式可以匹配整個(gè)字符串。

例:/^\s*$/

批注:用來(lái)匹配空白行,對所有的空白行來(lái)說(shuō)等效。如果不在前后加上兩個(gè)定位,則會(huì )把非空白行也一起算進(jìn)去。

(2)單詞定位

\b是單詞邊界定位,它匹配任何單詞的首尾。如/\bfred\b/可匹配fred,但無(wú)法匹配frederick、alfred、manfredmann。這稱(chēng)為整詞搜索模式。此處所說(shuō)的單詞是指一連串字母、數字與下劃線(xiàn)的組合,也就是匹配/\w+/模式的字符串。

例:That's a "word" boundary!

批注:該句子共5個(gè)單詞:That、s、a、word、boundary。要注意的是word兩邊的引號并不會(huì )改變單詞邊界。這些單詞是由一組\w字符構成的。

單詞定位很有用,不會(huì )使我們意外地在delicatessen中找到cat,在boondoggle中找到dog或在selfishness中找到fish。也可以只用到一個(gè)單詞邊界定位。如

/\bhunt/匹配hunt、hunting或hunter,而排除了shunt;用/stone\b/匹配standstone或flintstone,但不包括capstones。

4、綁定操作符

=~默認的情況下模式匹配的對象是$_,綁定操作符=~能讓Perl拿右邊的模式來(lái)匹配左邊的字符串,而非匹配$_。雖然它看起來(lái)像某種賦值運算,但并不是。它指的是本來(lái)這個(gè)模式會(huì )匹配$_變量,但請針對左邊的字符串匹配吧。若沒(méi)有綁定操作符,表達式就會(huì )使用默認的$_。

my $some_other = "I dream of betty rubble.";
if($some_other =~/\brub/){
    print "Aye, there's the rub.\n";}

在下面這個(gè)(不尋常的)例子里,$likes_perl會(huì )被賦予一個(gè)布爾值,這個(gè)結果取決于用戶(hù)鍵入的內容。這個(gè)程序屬于“急功近利”型的,因為判斷后就丟棄了用戶(hù)的輸入。這行代碼大致上的功能是讀取輸入行,匹配字符串與模式,然后舍棄輸入行的內容。沒(méi)有進(jìn)一步使用$_,也沒(méi)有改變它。

print "Do you like Perl?";
my $likes_perl = (<STDIN> =~ /\byes\b/i);
……  #耗時(shí)的其它程序……
if($likes_perl){
print "You said earlier that you like Perl,so..\n";}

批注:除非while循環(huán)的條件表達式中只有整行輸入操作符(<STDIN>),否則輸入行不會(huì )自動(dòng)存入$_。因為綁定操作符的優(yōu)先級相當高,也就沒(méi)必要用圓括號來(lái)跨住模式測試表達式。所以下面這一行如同上面的表達式一樣,會(huì )將匹配結果(而非輸入的內容)存進(jìn)變量。my $likes_perl = <STDIN> =~ /\byes\b/i;

5、模式串中的內插

#!/usr/bin/perl -w
my $what = "larry";
while(<>){
if(/^($what)/){
print "We saw $what in beginning of $_";}}

批注:不管$what的內容是什么,當我們進(jìn)行模式匹配的時(shí)候,該模式都會(huì )成為$what的值。在這里它和/^(larry)/是相同的意思,也就是在每行的開(kāi)頭尋找larry。

6、模式中變量的存儲

(1)捕獲變量

匹配變量(包括自動(dòng)匹配變量和帶編號的匹配變量)最常用在替換運算中。圓括號同時(shí)也啟動(dòng)了正則表達式處理引擎的捕獲功能。即把(圓括號中模式所匹配的)部分字符串暫時(shí)記下來(lái)的能力。如果有一對以上的圓括號,就會(huì )有一次以上的捕獲。

每個(gè)被捕獲的對象是原本的字符串,而不是模式。因為捕獲變量存儲的都是字符串,所以它們都是標量變量。在Perl里,它們的名字類(lèi)似$1或者$2。模式里的括號有多少對,匹配變量就有多少個(gè)。如$4就是第四對括號捕獲的字符串。這些變量能夠取出字符串里的某些部分,因此是正則表達式威力強大的重要原因之一。

$_="Hello there,neighbor";
if(/\s(\w+),/){   #捕獲空白符和逗號之間的單詞
print "the word was $1\n;"

批注:打印the word was there

也可以一次捕獲多個(gè)串。

$_="Hello there,neighbor";
if(/(\S+) (\S+), (\S+)/){   #捕獲空白符和逗號之間的單詞
print "the word was $1 $2 $3\n;"}

批注:讓我們知道這些單詞是Hello there neighbor。注意逗號的處理

my $dino="I fear that I'll be extinct after 1000 years.";
if($dino =~ /(\d*) years/){
    print "That said '$1' years.\n";   #$1為1000

my $dino="I fear that I'll be extinct after a few million years.";
if($dino =~ /(\d*) years/){
    print "That said '$1' years.\n";   

批注:$1為空字符串,而不是尚未定義。若模式中有三個(gè)一下的圓括號,$4才會(huì )是undef

(2)捕獲變量的生命期

這些捕獲變量通常能存活到下次成功的模式匹配為止。也就是說(shuō),失敗的匹配不會(huì )改動(dòng)上次成功匹配時(shí)捕獲的內容,而成功的匹配會(huì )將它們重置。如果對比失敗,它會(huì )輸出可能遺留在$1里的任何字符串。

$wilma = ~ /(\w+)/;  #不對!這里的結果不一定正確
        print "Wilma's word was $1...or was it?\n";

批注:這就是為什么模式匹配總是出現在if或while條件表達式里:

if($wilma =~ /(\w+)/){
    print "Wilma's word was $1.\n";}
else{
    print"Wilma doesn't have a word.\n";}

因為捕獲的內容不會(huì )永久留存,所以匹配變量只應該在模式匹配后的數行內使用。通常最好的做法是將它復制到某個(gè)一般的變量里。后面有更好的處理辦法,即模式匹配發(fā)生時(shí),直接將捕獲的內容存到變量中。

if($wilma =~ /(\w+)/){
my $wilma_word = $1;...}

(3)不捕獲模式

現在是每個(gè)括號的內容都會(huì )被變量捕獲,也可以設置某一個(gè)括號里的內容不被捕獲。

if(/(?:bronto)?saurus (steak|burger)/){
   print "Fred wants a $1\n";}

批注:這樣增減選項的時(shí)候就不用修改捕獲變量的名字了

if(/(?:bronto)?saurus (?:BBQ)?(steak|burger)/){
    print "Fred wants a $1\n";}

(4)命名捕捉

以上的變量捕捉方式有不好的地方。即使對于較為簡(jiǎn)單的模式來(lái)說(shuō),管理這樣的數字變量也是比較困難的。如下例:

use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) and (\w+)){ #不會(huì )匹配
    say "I saw $1 and $2";}

批注:不會(huì )看到say的輸出,因為模式里的and和實(shí)際變量中的or不匹配。我們考慮后認為兩者可以并存,加入“擇一”來(lái)匹配and或者or。當然需要在模式中加入一對括號。

use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) (and|or) (\w+)){
    say "I saw $1 and $2";}

批注:現在可以匹配了,但由于第二個(gè)括號的引入,是$2變量中的內容不是我們期望的了,期望的則進(jìn)入了$3。打印輸出I saw Fred and or,當然可以改為(?:and|or),但還是不方便。

Perl5.10引入了正則表達式命名捕捉的概念。現在捕捉的結果會(huì )進(jìn)入一個(gè)特殊的哈希%+,其中的鍵就是在捕捉時(shí)候使用的特殊標簽,其中的值就是被捕捉的串。為捕捉串加標簽的方法是使用(?<LABEL>PATTERN)這樣的寫(xiě)法,而LABEL可以自行命名。

use 5.010;
my $names = 'Fred or Barney';
if($names =~ m/(?<name1>\w+)) (?:and|or) (?<name2>\w+){
say "I saw $+{name1} and $+{name2}";}

批注:現在就能看到正確的結果:I saw Fred and Barney

一旦使用了捕捉標簽,就可以隨意移動(dòng)位置并加入更多的捕獲括號,不會(huì )因為括號的次序變化導致麻煩。

use 5.010;
my $names = 'Fred or Barney';
if($names =~ m/((?<name1>\w+)) (?:and|or) (?<name2>\w+)){
say "I saw $+{name1} and $+{name2}";}

批注:在使用捕捉標簽之后,也給反向引用帶來(lái)了更新的必要。之前我們使用\1或者g{1}這樣的寫(xiě)法,現在我們可以使用\g{label}這樣的寫(xiě)法。另外一種表示\k<lable>=\g{label}。

use 5.010;
my $names = 'Fred Flinstone and Wilma Flinstone';
if($names =~ m/(?<last_name>\w+) and \w+ \g{last_name}/){
say "I saw $+{last_name}";}

(5)自動(dòng)匹配變量

自動(dòng)匹配變量有可能是空字符串,它們的有效范圍也與標號的匹配變量相同。一般情況下,它們的值會(huì )一直持續到下一次模式匹配成功之前。

自動(dòng)匹配變量會(huì )拖慢其它正則表達式的運行速度,所以一般很少使用它們。

$&:字符串里實(shí)際匹配模式的部分會(huì )自動(dòng)存進(jìn)$&里。

if("Hello there, neighbor" =~ /\s(\w+),/){
    print "That actually matched '$&'.\n";}

批注:$&里匹配的部分是“ there,”(一個(gè)空格,一個(gè)單詞及一個(gè)逗號),相比之下,$1存儲的則只有單詞there,但$&里有整個(gè)的匹配段落。

$`:存儲匹配起始位置之前的字符串(保存了正則表達式引擎在找到匹配段落之前略過(guò)的部分)。

$':存儲匹配結束位置之后的字符串(保存了字符串中剩下的,從來(lái)沒(méi)有匹配到的部分)。

如果將這三個(gè)字符串依此連接起來(lái),就一定會(huì )得到原來(lái)的字符串。

if("Hello there, neighbor" =~ /\s(\w+),/){
    print "That was ($`)($&)($').\n";}

批注:會(huì )輸出(Hello)(there,)(neighbor)

7、通用量詞:花括號量詞

/a{5,15}/:匹配重復出現5到15次的字母a

/a{5,}/:至少5次,沒(méi)有上限,a之間不能有空格等額外符號

/a{8}/:匹配正好8個(gè)字符的單詞串

/,{5}chameleon/:匹配,,,,,chameleon

*={0,} +={1,} ?={0,1}

8、優(yōu)先級

優(yōu)先級告訴我們模式中哪些部分的緊密度最高。正則表達式的優(yōu)先級只有4個(gè)級別。

優(yōu)先級頂端的是(?),用來(lái)分組和捕獲。

第二級是量詞,也就是重復操作符:星號(*)、加號(+)、問(wèn)好(?)以及花括號量詞,像{5,15}、{3,}、{5}等。

第三極是定位與序列。定位包括:定位開(kāi)頭^,定位結尾$,詞邊界\b,非詞邊界\B。單詞里的字母之間和定位與字母之間的緊密程度是相同的。

最低的是“擇一”豎線(xiàn)(|)。因為是最低一級,它實(shí)際上會(huì )將模式拆分成數個(gè)部分。

完全沒(méi)有優(yōu)先級的就是那些組成模式的基本元素。包括每個(gè)獨立的字符,字符集和反向引用。

例:/^fred|barney$/

批注:要么匹配字符串開(kāi)頭的fred,要么匹配字符串結尾的barney。

例:/^(fred|barney)$/

批注匹配只包含fred或是只包含barney的每一行。

例:/(wilma|pibbles?)/

批注:匹配willma、pebbles一級pebble這三個(gè)字符串,或是長(cháng)字符串的一部分(因為模式中沒(méi)有定位)。

例:/^(\w+)\s+(\w+)$/

批注:匹配開(kāi)始是一個(gè)單詞,再來(lái)一些空白,然后又是一個(gè)單詞的行。如fred flintstone之類(lèi)的字符串。這里的圓括號并不是為了分組而存在,可能只是為了把匹配的字符串給捕獲下來(lái)。

在嘗試理解一個(gè)很復雜的模式時(shí),試著(zhù)加上一些括號會(huì )對弄清楚優(yōu)先級有好處。但請記住,圓括號同時(shí)也會(huì )有捕獲的效果。因此建議盡可能用非捕獲的圓括號來(lái)分組。

(9)模式測試程序

下面是一個(gè)有用的程序,可用來(lái)檢測某些字符串是否能被指定的模式匹配。

#!/usr/bin/perl
while(<>){
    chomp;
    if(/YOUR_PATTERN_GOES_HERE/){
       print "Matched: |$`<$&>$'|\n";}
    else{
       print "No match: |$_|\n";}
香格里拉县| 岳西县| 彭水| 罗定市| 吐鲁番市| 祁连县| 泊头市| 广宗县| 大田县| 张掖市| 青田县| 齐齐哈尔市| 景泰县| 泊头市| 遂溪县| 榕江县| 乐平市| 罗源县| 大连市| 上虞市| 瑞昌市| 肥东县| 望城县| 遂昌县| 浦城县| 囊谦县| 溧阳市| 郴州市| 新龙县| 吕梁市| 武威市| 乌什县| 澄城县| 江北区| 淮阳县| 庆安县| 方城县| 咸阳市| 富平县| 饶平县| 梨树县|