python與perl語言,字符串轉義與正則匹配轉義混合探究

前言

平時寫腳本,經常會被正則匹配中的轉義弄得頭大,因此基於perl和python的字符串轉義和正則匹配轉義探究一下轉義的規則。

字符串轉義

腳本語言的字符串轉義基本是通用的,菜鳥教程中羅列了一下基本的轉義字符:

轉義字符 描述
\(在行尾時) 續行符
\\ 反斜槓符號
\' 單引號
\" 雙引號
\a 響鈴
\b 退格(Backspace)
\e 轉義
\000
\n 換行
\v 縱向製表符
\t 橫向製表符
\r 回車
\f 換頁
\oyy 八進制數,yy代表的字符,例如:\o12代表換行
\xyy 十六進制數,yy代表的字符,例如:\x0a代表換行
\other 其它的字符以普通格式輸出

 當使用轉義方式表達字符串時,便會呈現轉義效果,例如在python3中直接鍵入打印語句:

print('http:\\\\sscc.com\tcompile\\t.com')

打印效果如下:

由於python不通過 ‘ “ 來區分轉義符,因此以下兩種打印結果時一致的:

print('http:\\\\sscc.com\tcompile\\t.com')
print("http:\\\\sscc.com\tcompile\\t.com")

打印效果如下:

而perl是通過 ' ' 和 " ” 來區分字符串轉義,因此以下兩種揭發打印結果不同,“ 中字符串會進行字符串轉義, ' 中的字符串不會進行字符串轉義:

print "in \", lets print: http:\\\\sscc.com\tcompile\\t.com\n";
print 'in \', lets print: http:\\\\sscc.com\tcompile\\t.com\n';

打印效果如下:

不過直接說 “ " 中字符串會進行字符串轉義, ' ' 中的字符串不會進行字符串轉義也不完美,有特殊的情況,一是 \' \"這兩個轉義符都會轉義,二是 \\ 這個在兩個打印中都進行了轉義。

關於perl中 \\ 在 ' '  和 " " 中的效果,我們看兩個例子。首先可以看下在 ' ' 中使用:

print 'in \', lets print: http:\sscc.com\tcompile\\t.com\n';
print "\n";
print 'in \', lets print: http:\\sscc.com\tcompile\\t.com\n';
print "\n";
print 'in \', lets print: http:\\\sscc.com\tcompile\\t.com\n';
print "\n";
print 'in \', lets print: http:\\\\sscc.com\tcompile\\t.com\n';
print "\n";

打印效果如下:

可以發現,\\被轉義爲\,\\\\被轉義爲\\,這個知其然就好了我沒有去查相關的說明。

其次看下在 " " 中轉義\\的效果:

print "in \", lets print: http:\sscc.com\tcompile\\t.com\n";
print "in \", lets print: http:\\sscc.com\tcompile\\t.com\n";
print "in \", lets print: http:\\\sscc.com\tcompile\\t.com\n";
print "in \", lets print: http:\\\\sscc.com\tcompile\\t.com\n";

打印效果如下:

可以發現這是很標準的字符串轉義,單個\使用時會跟下一個字符(串)檢查是否又轉義存在,如果不存在\直接不打印否則打印轉義後效果,\\一起使用時第一個\將第二個\轉義爲 不帶有任何轉義意義的反斜槓符號 本身,\\\一起使用第一個\將第二個轉義爲反斜槓符號 第三個和後面不構成轉義符因此不打印,\\\\就不分析了。

上面說的perl中的效果,python中不區分' '和" "的,那麼如何判定是否轉義呢?通過前綴符號r來區分,看下下面的代碼:

print(r"http:\sscc.com\tcompile\\t.com")
print(r"http:\\sscc.com\tcompile\\t.com")
print(r"http:\\\sscc.com\tcompile\\t.com")
print(r"http:\\\\sscc.com\tcompile\\t.com")

打印效果如下:

可以發現python對於字符串轉義隔離的很清晰,使用r前綴後,所以字符只表示本身而不帶有任何字符串轉義效果。

python中正則匹配轉義

下面還是摘以下菜鳥教程的表,正則匹配中常用轉義符有以下這些:

\w 匹配字母數字及下劃線
\W 匹配非字母數字及下劃線
\s 匹配任意空白字符,等價於 [\t\n\r\f].
\S 匹配任意非空字符
\d 匹配任意數字,等價於 [0-9].
\D 匹配任意非數字
\A 匹配字符串開始
\Z 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。
\z 匹配字符串結束
\G 匹配最後匹配完成的位置。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等. 匹配一個換行符。匹配一個製表符。等
\1...\9 匹配第n個分組的內容。
\10 匹配第n個分組的內容,如果它經匹配。否則指的是八進制字符碼的表達式。

 這個就不用細說了,我們主要探究的是字符串轉義和正則轉義混合時候的情況,先來看一組測試效果我們再來慢慢分析:

if re.search('\\\\d+', 'http:\d+baidu.com'):
	print('match 1')
	
if re.search('\\d+', 'http:\d+baidu.com'):
	print('match 2')
	
if re.search('\\d+', 'http:baidu360.com'):
	print('match 3')
	
if re.search(r'\d+', 'http:baidu360.com'):
	print('match 4')
	
if re.search(r'\d+', 'http:\d+baidu.com'):
	print('match 5')
	
if re.search(r'\\d+', 'http:\d+baidu.com'):
	print('match 6')

打印效果如下:

那麼我們來看下,從第一個和第二個一起看下,我想要用不帶前綴r的形式(即帶字符串轉義的若干字符)進行匹配字符串 \d+,第一種方式成功了而第二種沒有成功。

if re.search('\\\\d+', 'http:\d+baidu.com'):
	print('match 1')

再分析下\\\\,前兩個\\通過字符串轉義變爲反斜槓符號\,後兩個\\同樣翻譯爲反斜槓符號\,那麼經過字符串轉義後變成了匹配\\d+,那麼再進行正則匹配轉義;正則匹配轉義中\\表示\(即不對後面進行正則轉義的普通反斜槓),那麼我們就成功的匹配到了後面字符中的\d+。

if re.search('\\d+', 'http:\d+baidu.com'):
	print('match 2')

經過前面的分析就很容易得出第二個爲什麼無法匹配到\d+了,因爲經過字符串轉義後\\d+變成了\d+,而後進行正則轉義的時候\d+被轉義爲”1個或以上的數字“,因此自然無法匹配字符串\d+。

if re.search('\\d+', 'http:baidu360.com'):
	print('match 3')

結合第三個看就更加明顯了,第三個就能夠匹配。

所以我們發現,如果字符串轉義和正則轉義參雜在一起,有的時候很繁瑣,因此一般我都會採用前綴r的方式使之忽略字符串轉義。

if re.search(r'\d+', 'http:baidu360.com'):
	print('match 4')
	
if re.search(r'\d+', 'http:\d+baidu.com'):
	print('match 5')
	
if re.search(r'\\d+', 'http:\d+baidu.com'):
	print('match 6')

忽略字符串轉義的效果就如同後三個實驗一樣了,\d+直接翻譯爲”1個或以上的數字“去匹配後面的數字,\\d+纔會匹配到後面的字符串\d+。

上面的實驗是匹配是否帶前綴r的問題,其實後面一樣可以帶前綴r,看個例子就就明白了:

if re.search(r'\\n', r'http:\nbaidu.com'):
	print('match 7')
if re.search(r'\\n', 'http:\nbaidu.com'):
	print('match 8')

打印結果如下:

可見,當被匹配項有前綴r的時候,其中的\n沒有被翻譯爲換行,因此可以被\n匹配到;而不加r的話就被字符轉轉義翻譯爲換行,那麼顯然不能被匹配到了。

perl中正則匹配轉義

perl的效果我們直接看例子:

$line1 = "http:baidu360.com";
if ($line1 =~ /\d+/){
	print("match 1\n")
}
$line2 = "http:baidu\d+.com";
if ($line2 =~ /\d+/){
	print("match 2\n")
}
$line3 = 'http:baidu\d+.com';
if ($line3 =~ /\\d+/){
	print("match 3\n")
}

打印效果如下:

可以發現,就是 /匹配項/ 默認採用的是忽略字符串轉義,前面的被匹配項根據你賦值時候的是使用的' '還是" "有所區別," "的時候會先把被匹配項做字符串轉義。

結語

實驗做累了,就寫到這吧。

總結來說呢,perl中的匹配項默認是忽略字符串轉義的,python中根據有無前綴r來判定。

而shell和tcl我記得是默認帶着字符串轉義的,所以總看到shell裏面各種/\\d+\\w+/什麼的,不知道有沒有記錯。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章