讀古今文學網 > 精通正則表達式(第3版) > Substitution運算符 >

Substitution運算符

The Substitution Operator

Perl的substitution運算符s/…/…/不但能夠匹配,還能夠替換匹配的文字。通常的形式是:

$text=~s/regex/replacement/modifiers

簡單來說,regex 匹配的文本會替換為 replacement 的值。如果使用了/g,這個正則表達式會重複應用到文本中進行匹配,每次匹配的內容都會被替換。

與 match 操作一樣,如果目標字符串在變量$_中,目標運算元和=~都不是必須的。match運算符可以省略m,而substitution不能省略s。

我們已經看到,match運算符是非常複雜的——它的工作原理,它的返回值,都取決於它所在的應用場合,目標字符串的pos,以及使用的修飾符。相反,substitution運算符很簡單:它返回的信息是不變的(表示替換的次數),影響它的修飾符也很好理解。

你可以使用第292頁介紹的所有核心修飾符,但是substituion運算符還支持另外兩個修飾符,/g,以及馬上將要介紹的/e。

運算元replacement

The Replacement Operand

在普通s/…/…/中,replacement緊跟在regex之後;m/…/使用兩個分隔符,而這裡要使用3個。如果正則表達式使用對稱的分隔符(例如<…>),則replacement有自己的一對分隔符(這樣總共就有4個分隔符)。舉例來說,s{…}{…}和s[…]/…/和s<…>\'…\'都是合法的。這種情況下,兩對分隔符可以用空白字符分隔,如果使用了空白字符,還可以添加註釋。對稱的分隔符通常在/x或/e中使用。

請注意區分regex和replacement。regex會按照正則表達式的方式來解析,有自己的分隔符(☞291)。replacement 則會當作普通的雙引號字符串來解析和求值(evaluate)。求值會在匹配之後進行(如果使用了/g,每次匹配之後都會求值),所以$1之類的變量能夠指向對應的匹配內容。

在下面兩種情況下,replacement不會按照雙引號字符串來解析:

●replacement的分隔符是單引號,此時作為單引號字符串,不會進行變量插值。

●使用了/e修飾符(下一節討論),replacement會作為一小段Perl代碼而不是雙引號字符串。這一小段Perl代碼會在每次匹配之後執行,結果作為replacement。

/e修飾符

The/e Modifier

/e修飾符會把replacement作為一段Perl代碼來進行求值,這就類似eval{…}。代碼裝載時,首先會檢查這段代碼的語法,確保沒有錯誤,但是每次匹配之後都會對代碼重新求值。每次匹配之後,replacement都會在scalar context中重新求值,結果作為replacement。下面有個簡單的例子:

$text=~s/-time-/localtime/ge;

在scalar context中,它會用Perl的localtime函數的結果(也就是返回表示當前時間的文本,例如「Mon Sep 25 18:36:51 2006」)替換「-time-」。

因為求值是每次匹配之後進行的,我們可以通過$1等變量引用匹配的內容。例如,URL中不容許出現的特殊字符,可以編碼為百分號「%」加兩位十六進制數的形式。為了編碼所有這種字符,可以這樣:

$url=~s/([^a-zA-Z0-9])/sprintf(\'%%%02x\',ord($1))/ge;

下面的程序可以用來解碼:

$url=~s/%([0-9a-f][0-9a-f])/pack(〞C〞,hex($1))/ige;

簡單地說,sprintf(\'%%%02x\',ord(character))把字符轉換為對應的 URL 編碼,而pack(〞C〞,value)的作用相反,請參考你常用的Perl文檔獲取更多信息。

多次使用/e

通常情況下,對單個運算符多次使用同一修飾符沒有特殊意義(只有讓讀者更困惑),但是重複/e修飾符卻會改變replacement的替換過程。正常情況下,replacement會進行一次求值,但是如果『e』的數目多於1個,則Perl又會對求值的結果進行求值,如此一直進行下去,求值的次數與『e』的數目一樣多。或許它的主要價值是用作比較Perl代碼複雜性的測試。

不過此功能並非完全無用。如果需要手動進行變量插值(例如從配置文件讀入字符串)。也就是說,有一個字符串『…$var…』,我們希望把『$var』替換為$var的值。

簡單的辦法是:

$data=~s/($[a-zA-Z_]w*)/$1/eeg;

如果不使用/e,則會替換匹配的『$var』自身,這沒什麼用。使用一個/e,會對$1重新求值,得到『$var』,這樣也沒什麼意義,同樣是用匹配的文本替換自身。但是如果使用兩個/e,則『$var』會重新求值,得到內容,這樣就模擬了變量插值。

應用場合與返回值

Context and Return Value

根據 context和/g的不同組合,match運算符會返回不同的值。不過,substitution運算符沒有這麼複雜——它返回的要麼是替換發生的次數,要麼是空字符串,表示沒有發生任何替換。

為使用方便,返回值為Boolean時(例如在if條件語句中),只要發生了替換,返回值就為true,false表示沒發生替換。