基礎正則表達式

本文介紹基礎正則表達式,沒有示例(),只有總結和"解惑",若是想學習更強大、更完整的正則,能夠參考:Perl正則超詳細教程grep -P、ack都支持Perl正則,且不少須要使用到正則的服務軟件通常都採用PCRE(如httpd、nginx、haproxy、proxysql),它和Perl正則幾乎徹底一致,做爲運維人員,我以爲是有必要學上一學的。html

基礎正則

元字符:

  • .:匹配任意單個字符,但不能匹配換行符\n
  • *:匹配前面那個字符0或屢次
  • ?:匹配前面那個字符0或一次
  • +:匹配前面那個字符1次以上
  • {M,N}:匹配前面那個字符至少M,最多N次
  • {M,}:匹配前面那個字符至少M次,最多無限制
  • {,N}:匹配前面那個字符最多N次(最少固然是0次)。注意,perl正則不支持這種方式
  • {M}:匹配前面那個字符正好M次
  • 錨定:錨定的意思是匹配位置,而非匹配字符實體
    • ^:匹配行首位置,注意匹配的是位置,不是字符
    • $:匹配行尾位置,注意匹配的是位置,不是字符

特殊且經常使用的的組合正則表達式:java

  • ^$:它表示匹配空行
  • .*:匹配任意長度的任意字符,但不能匹配換行符。真正的匹配任意長度的任意字符,見下面

須要解釋清楚的是這些量詞(也就是上面匹配的次數元字符)的特殊性:當使用了匹配屢次的量詞時(如匹配3-5次的{3,5}),且量詞前面的字符有多種可能性(如中括號序列[abc]),那麼量詞的次數能夠做用於任一字符。有些很差理解,但看示例就知道了:python

[abc]{3,5}     # 表示abc任意字符均可以出現,好比全是a,或者ab同時出現,但總的出現次數爲3-5次
.*          # 表示任一字符(除換行符),能夠任意出現任意次數,它不表示a以後就必須全是a
.+          # 表示任一字符(除換行符),能夠任意出現至少一次,它不表示a以後就必須全是a

另外,.沒法匹配換行符。可能你不太理解爲何須要匹配換行符,它主要用在:nginx

  1. 多行模式。例如sed的多行模式下,要跨行匹配須要手動指定"\n",如/^a.*\nb.*/
  2. 明確指定了行分隔符爲非"\n"的狀況。例如awk可使用RS變量指定輸入行分隔符

中括號

中括號表示的是匹配任意一個,通常它和字符集的排序規則有關,不一樣工具採起的排序規則可能也不同。git

  • [abcd...]:匹配中括號內的任意一個字符
  • [^abcd...]:拒絕匹配中括號內的任意字符
  • [a-z]:匹配字母a到z
  • [A-Z]:匹配字母A到Z
  • [0-9]:匹配0-9,也就是匹配數字

關於字母的排序:正則表達式

  • perl中,A-Z排在a的前面,因此[A-z]表示全部大小寫字母
  • grep中,A-Z排在z的後面,因此[a-Z]表示全部大小寫字母
  • 還有些工具中,大小寫的排序規則是aAbBcC...zZ,因此[a-C]表示aAbBcC共6個字母

字符類

是專門命名的中括號序列;除了字符類,還有等價類、排序類,但基本用不上,只用字符類。sql

  • [:alpha:]:匹配字母,等價於[a-zA-Z]
  • [:digit:]:匹配數字,等價於[0-9]
  • [:xdigit:]:匹配十六進制數,等價於[0-9a-fA-F]
  • [:upper:]:匹配大寫字母,等價於[A-Z]
  • [:lower:]:匹配小寫字母,等價於[a-z]
  • [:alnum:]:匹配數字或字母,等價於[0-9a-zA-Z]
  • [:blank:]:匹配空白,包括空格和製表符
  • [:space:]:匹配空格,包括空格、製表符、換行符、回車符等各類類型的空白
  • [:punct:]:匹配標點符號。包括:! ' " ` # $ % & ( ) * + , . - _ / : ; < = > ? @ [ \ ] ^ { | } ~
  • [:graph:]:繪圖類。包括:大小寫字母、數字和標點符號。等價於[:alnum:]+[:punct:]
  • [:print:]:打印字符類。包括:大小寫字母、數字、標點符號和空格。等價於[:alnum:]+[:punct:]+space
  • [:cntrl:]:控制字符類。在ASCII中,這些字符的八進制代碼從000到037,還包括177(DEL)

須要注意的是,一般字符類在真正使用過程當中,會再加上一個中括號,例如[[:alpha:]]。之因此如此,是由於這些字符類只是一種命名好的字符集合。例如[:lower:]對應的字符集合是a-z,而不是[a-z],因此要想讓其表示這些命名字符類中的任一字符,須要再加上一層括號[[:lower:]],它纔等價於[a-z]。可能會更有助於理解使用字符類的時候爲何要加兩個中括號的例子是[^[:lower:]],它表示不包含任何小寫字母。編程

反斜線序列

不一樣的工具,同一工具不一樣的版本,支持的反斜線序列能力不一樣。如下列出了部分常見序列。運維

如下所說的單詞,通常來講只包含數字、字母和下劃線,即[_0-9a-zA-Z]編程語言

如下幾種反斜線序列,基本上全部工具都支持:

  • \b:匹配單詞邊界處的空字符
  • \B:匹配非單詞邊界處的空字符
  • \<:匹配單詞開頭處的空字符
  • \>:匹配單詞結尾處的空字符
  • \w:匹配單詞構成部分,等價於[_[:alnum:]]
  • \W:匹配非單詞構成部分,等價於[^_[:alnum:]]

如下幾種,有些工具不支持,但perl都支持:

  • \s:匹配空白字符,等價於[[:space:]]
  • \S:匹配非空白字符,等價於[^[:space:]]
  • \d:匹配數字,等價於[0-9]
  • \D:匹配非數字,等價於[^0-9]

因爲元字符.默認沒法匹配換行符,因此須要匹配換行符的時候,可使用特殊組合[\d\D]來替換.,換句話說,若是想匹配任意長度的任意字符,能夠換成[\d\D]*,固然,前提是必須支持\d\D兩個反斜線序列。

分組捕獲和反向引用

基礎正則中,使用括號能夠對匹配內容進行分組並暫時保存,分組後會有分組編號,可使用反斜線加編號\N的方式反向引用這些分組。

分組編號的方式是從左向右計算括號數,不管如何嵌套,第一個左括號對應的分組必定是編號1,用\1來引用,第二個左括號對應的分組必定是編號2,用\2來引用,依此類推。

例如grep的分組捕獲:匹配兩個連續相同的字母。

echo "abcddefg" | grep -E "(.)\1"

能夠認爲分組就是變量賦值的過程。例如,上面示例的匹配過程以下:
1.匹配第一個字母a,放進分組,即賦值給變量(假設變量名爲$1),即$1="a",再繼續執行正則表達式匹配過程的反向引用,它引用的是$1,因而表示第一個字母a後面還要是字母a,因而匹配失敗。
2.匹配第二個字母b,放進分組,即$1="b",再匹配後一個字母,因而匹配失敗。
3.字母c一樣如此。
4.匹配字母d,放進分組,即$1="d",再匹配後一個字母,發現匹配成功,因而$1被保存下來。
5.已經匹配成功,因而結束。

對於只使用基礎正則的工具來講,通常都只能引用\1\9共9個反向引用,最多本身額外提供一個全部表示匹配內容的反向引用(例如sed提供的&)。對於超出10個的分組,使用基礎正則的工具通常來講是無能爲力的。

再者,基礎正則僅僅只是將分組匹配到的內容捕獲,在正則操做結束後就丟失。但對於一門完整編程語言來講,這遠遠不夠,幾乎全部編程語言(如perl/java/python等)都會將正則的分組匹配內容保存爲變量,使得能夠在正則結束以後再次引用甚至修改它們。例如上面例子中分組捕獲的字母d,若是換成perl,即便在這個匹配過程結束後,仍是能夠去引用這段分組。

二選一

  • pattern1 | pattern2:匹配豎線左邊,或者匹配豎線右邊都算匹配成功

關於二選一的結構,幾點須要說明:

  1. 由於豎線元字符的優先級很低,因此ab|cd匹配的是"ab"或"cd",而不是abd或acd。
  2. 成功匹配了左邊,就不會再去對右邊進行匹配。
  3. 反向引用失敗問題:豎線將兩邊的分組隔開,右邊的永遠沒法反向引用左邊的分組

在二選一結構種,兩個反向引用問題的典型例子:

例如a(.)|b\1將沒法匹配"ba",由於評估了左邊就不會評估右邊。

例如([ac])e\1|b([xyz])\2t的左邊能匹配aea或cec,但不能匹配cea或aec,右邊能匹配bxxt或byyt或bzzt。但若是將\2換成\1,即([ac])e\1|b([xyz])\1t,將沒法匹配b[xyz]at或b[xyz]ct,由於第一個分組括號在左邊,沒法參與右邊的正則評估。

相關文章
相關標籤/搜索