正則表達式


什麼是正則表達式

正則表達式是一種特殊的字符串模式,用於匹配一組字符串,簡單的說,正則表達式是一種符號表示法,用於識別文本模式,在某種程度上,它們類似於匹配文件和路徑名時使用的shell通配符,但其用途更廣泛。
常用正則匹配軟件:Match Tracer
下載地址 : http://www.regexlab.com/zh/mtracer/


grep 文本搜索

在linux上,用來處理正則表達式的主要程序是grep,grep搜索文本文件中與指定正則表達式匹配的行,並將結果送至標準輸出

grep [option] regex [file...]
ls /usr/bin | grep zip //利用grep搜索固定的字符串zip 並將結果輸出
常用參數 意義
-i 忽略大小寫
-v 不匹配的。。
-c 輸出匹配項數目,也可以用–count 指定
-n 在每個匹配行前面加上行號
-h 多文件索搜時,抑制文件名輸出

grep -v "#" /etc/vsftpd/vsftpd.conf_bak > /etc/vsftpd/vsftpd.conf //去掉#號並將結果輸出到另一個文件
grep bzip dirlist*.txt  //對文件表進行搜索字符串bzip

正則表達式之元字符

正則表達式的元字符包括以下字符 ^ $ . [ ] { } ~ ? * + ( ) | \

     "^" :^會匹配行或者字符串的起始位置,有時還會匹配整個文檔的起始位置。 
     "$"  :$會匹配行或字符串的結尾
     ".":匹配除了換行符以外的任何字符.這個算是"\w"的加強版了,"\w"不能匹配 空格 如果把字符串加上空格用"\w"就受限了,看下用 "."是如何匹配字符  "a23 4 5 B C D__TTz"   正則:".+"
    "[abc]": 字符組  匹配包含括號內元素的字符 這個比較簡單了只匹配括號內存在的字符,還可以寫成[a-z]匹配a至z的所以字母就等於可以用來控制只能輸入英文了,[A-Z] 等等
    "*" : 代表任意字符
    正則表達式 "^?"(行開頭和行結尾之間沒有字符),將會匹配空行
    否定:如果中括號的第一個字符是插入符 "^" 那麼剩下的字符則被當作不應該在指定位置出現的字符: "[^abc]"  匹配除了abc以外的任意字符
    幾種反義:  
    "\W"   匹配任意不是字母,數字,下劃線 的字符;  
    "\S"   匹配任意不是空白符的字符;  
    "\D"  匹配任意非數字的字符;  
    "\B"  匹配不是單詞開頭或結束的位置

“\b” :不會消耗任何字符只匹配一個位置,常用於匹配單詞邊界 如 我想從字符串中”This is Regex”匹配單獨的單詞 “is” 正則就要寫成 “\bis\b”

\b 不會匹配is 兩邊的字符,但它會識別is 兩邊是否爲單詞的邊界

“\d”: 匹配數字,

例如要匹配一個固定格式的電話號碼以0開頭前4位後7位,如0737-5686123 正則:^0\d\d\d-\d\d\d\d\d\d\d$ 這裏只是爲了介紹”\d”字符,實際上有更好的寫法會在 下面介紹。

“\w”:匹配字母,數字,下劃線.

例如我要匹配”a2345BCD__TTz” 正則:”\w+” 這裏的”+”字符爲一個量詞指重複的次數,稍後會詳細介紹。
“\s”:匹配空格

例如字符 “a b c” 正則:”\w\s\w\s\w” 一個字符後跟一個空格,如有字符間有多個空格直接把”\s” 寫成 “\s+” 讓空格重複


量詞

先解釋關於量詞所涉及到的重要的三個概念

貪婪(貪心) 如”*”字符 貪婪量詞會首先匹配整個字符串,嘗試匹配時,它會選定儘可能多的內容,如果 失敗則回退一個字符,然後再次嘗試回退的過程就叫做回溯,它會每次回退一個字符,直到找到匹配的內容或者沒有字符可以回退。相比下面兩種貪婪量詞對資源的消耗是最大的,

懶惰(勉強) 如 “?” 懶惰量詞使用另一種方式匹配,它從目標的起始位置開始嘗試匹配,每次檢查一個字符,並尋找它要匹配的內容,如此循環直到字符結尾處。

佔有 如”+” 佔有量詞會覆蓋事個目標字符串,然後嘗試尋找匹配內容 ,但它只嘗試一次,不會回溯,就好比先抓一把石頭,然後從石頭中挑出黃金


“|” 或者

“*”(貪婪) 重複零次或更多

例如”aaaaaaaa” 匹配字符串中所有的a 正則: “a*” 會出到所有的字符”a”

“+”(懶惰) 重複一次或更多次

例如”aaaaaaaa” 匹配字符串中所有的a 正則: “a+” 會取到字符中所有的a字符, “a+”與”a*”不同在於”+”至少是一次而”*” 可以是0次,

“?”(佔有) 重複零次或一次

例如”aaaaaaaa” 匹配字符串中的a 正則 : “a?” 只會匹配一次,也就是結果只是單個字符a

“{n}” 重複n次

例如從”aaaaaaaa” 匹配字符串的a 並重復3次 正則: “a{3}” 結果就是取到3個a字符 “aaa”;

“{n,m}” 重複n到m次

例如正則 “a{3,4}” 將a重複匹配3次或者4次 所以供匹配的字符可以是三個”aaa”也可以是四個”aaaa” 正則都可以匹配到

“{n,}” 重複n次或更多次

與{n,m}不同之處就在於匹配的次數將沒有上限,但至少要重複n次 如 正則”a{3,}” a至少要重複3次

把量詞瞭解了之後之前匹配電話號碼的正則現在就可以改得簡單點了^0\d\d\d-\d\d\d\d\d\d\d可以改爲”0\d+−\d7可以改爲”0\d+−\d7”。

這樣寫還不夠完美如果因爲前面的區號沒有做限定,以至於可以輸入很多們,而通常只能是3位或者4位,

現在再改一下 “^0\d{2,3}-\d{7}”如此一來區號部分就可以匹配3位或者4位的了


懶惰限定符

"*?"   重複任意次,但儘可能少重複 

如 "acbacb"  正則  "a.*?b" 只會取到第一個"acb" 原本可以全部取到但加了限定符後,只會匹配儘可能少的字符 ,而"acbacb"最少字符的結果就是"acb" 

"+?"  重複1次或更多次,但儘可能少重複

與上面一樣,只是至少要重複1次

"??"  重複0次或1次,但儘可能少重複

如 "aaacb" 正則 "a.??b" 只會取到最後的三個字符"acb"

"{n,m}?"  重複n到m次,但儘可能少重複

如 "aaaaaaaa"  正則 "a{0,m}" 因爲最少是0次所以取到結果爲空

"{n,}?"    重複n次以上,但儘可能少重複

如 "aaaaaaa"  正則 "a{1,}" 最少是1次所以取到結果爲 "a"

正則進階

先了解在正則中捕獲分組的概念,其實就是一個括號內的內容 如 “(\d)\d” 而”(\d)” 這就是一個捕獲分組,可以對捕獲分組進行 後向引用 (如果後而有相同的內容則可以直接引用前面定義的捕獲組,以簡化表達式) 如(\d)\d\1 這裏的”\1”就是對”(\d)”的後向引用

那捕獲分組有什麼用呢看個例子就知道了

如 “zery zery” 正則 \b(\w+)\b\s\1\b 所以這裏的”\1”所捕獲到的字符也是 與(\w+)一樣的”zery”,爲了讓組名更有意義,組名是可以自定義名字的

“\b(?\w+)\b\s\k\b” 用”?”就可以自定義組名了而要後向引用組時要記得寫成 “\k”;自定義組名後,捕獲組中匹配到的值就會保存在定義的組名裏

下面列出捕獲分組常有的用法

"(exp)"    匹配exp,並捕獲文本到自動命名的組裏

"(?<name>exp)"   匹配exp,並捕獲文本到名稱爲name的組裏

"(?:exp)"  匹配exp,不捕獲匹配的文本,也不給此分組分配組號

以下爲零寬斷言

"(?=exp)"  匹配exp前面的位置

如 “How are you doing” 正則”(?.+(?=ing))” 這裏取ing前所有的字符,並定義了一個捕獲分組名字爲 “txt” 而”txt”這個組裏的值爲”How are you do”;

    "(?<=exp)"  匹配exp後面的位置

如 “How are you doing” 正則”(?(?<=How).+)” 這裏取”How”之後所有的字符,並定義了一個捕獲分組名字爲 “txt” 而”txt”這個組裏的值爲” are you doing”;

    "(?!exp)"  匹配後面跟的不是exp的位置

    如 "123abc" 正則 "\d{3}(?!\d)"匹配3位數字後非數字的結果

    "(?<!exp)"  匹配前面不是exp的位置

    如 "abc123 " 正則 "(?<![0-9])123" 匹配"123"前面是非數字的結果也可寫成"(?!<\d)123"

POSIX字符類

傳統的字符範圍表示方法很容易理解,而且能夠有效、快速地指定字符集。但不足之處在於,它並不是所有情況都適用。

[me@linuxbox ~]$ ls /usr/sbin/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*

/usr/sbin/MAKEFLOPPIES

/usr/sbin/NetworkManagerDispatcher

/usr/sbin/NetworkManager

Linux發行版本不同,上述命令行得到的結果可能會不同,甚至有可能是空列表。本例中的列表來自於Ubuntu系統。該命令行得到了預期效果—只有以大寫字母開頭的文件列表。但是,如果我們使用下面的命令行,便會得到完全不同的結果(只顯示了輸出結果的一部分)。

[me@linuxbox ~]$ ls /usr/sbin/[A-Z]*

/usr/sbin/biosdecode

/usr/sbin/chat

/usr/sbin/chgpasswd

/usr/sbin/chpasswd

/usr/sbin/chroot

/usr/sbin/cleanup-info

/usr/sbin/complain

/usr/sbin/console-kit-daemon

爲什麼會出現這樣的差異?說來話長,簡單解釋如下。

在UNIX開發初期,它只識別ASCII字符,而正是這一特性導致了上面的差異。在ASCII碼中,前32個字符(第0~31字符)都是控制字符(像Tab鍵、空格鍵以及Enter鍵等),後32個字符(第32~63)包含可打印字符,包括大多數的標點符號以及數字0~9,接下來的32個(第64~95)包含大寫字母和一些標點符號,最後的31個(第96~127)則包含小寫字母以及更多的標點符號。基於這樣的安排,使用ASCII的系統使用了下面這種排序:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

這與通常的字典順序不一樣,字典中字母的順序表通常如下。

aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ

隨着UNIX在美國以外國家的普及,人們越來越希望計算機能支持美式英語中找不到的字符。於是,ASCII字符表也得以擴展,開始使用 8 位二進制來表示,這也就增加了第 188~255 的字符,兼容了更多的語言。爲了支持這種功能,POSIX標準引入了域(locale)的概念,它通過不停調整以選擇特定的位置所需要的字符集。我們可以使用下面的命令行查看系統的語言設置。

[me@linuxbox ~]$ echo $LANG

en_US.UTF-8

有了這個設置,POSIX兼容的應用程序使用的便是字典中的字母排列順序,而不是用ASCII碼中的字符排列順序。這樣,便解釋了上面命令行的詭異行爲。A~Z的字符範圍,用字典中的順序詮釋時,包括了字母表中除了小寫字母a的所有字母,因此使用命令行ls /usr/sbin/[A-Z]*纔會出現全然不同的結果。

爲了解決這一問題,POSIX標準包含了許多標準字符類,這些字符類提供了一些有用的字符範圍,如下:

字符類 描述
[:alnum:] 字母字符和數字字符;在ASCII碼中,與[A-Za-z0-9]等效
[:word:] 基本與[:alnum:]一樣,只是多了一個下劃線字符(_)
[:alpha:] 字母字符;在ASCII中,等效於[A-Za-z]
[:blank:] 包括空格和製表符
[:cntrl:] ASCII控制碼;包括ASCII字符0~31以及127
[:digit:] 數字0~9
[:graph:] 可見字符;在ASCII中,包括字符33~126

續表

字符類 描述
[:lower:] 小寫字母
[:punct:] 標點符號字符;在ASCII中,與[-!”#$%&’()*+,./:;<=>?@[\]_`{
[:print:] 可打印字符;包括[:graph:]中的所有字符再加上空格字符
[:space:] 空白字符如空格符、製表符、回車符、換行符、垂直製表符以及換頁符。在ASCII中,等效爲[ \t\r\n\v\f]
[:upper:] 大寫字母
[:xdigit:] 用於表示十六進制的字符;在ASCII中,與[0-9A-Fa-f]等效

使用字符類,我們可以重複上述大寫字母的例子,並得到改善的輸出結果。


[me@linuxbox ~]$ ls /usr/sbin/[[:upper:]]*

/usr/sbin/MAKEFLOPPIES

/usr/sbin/NetworkManagerDispatcher

/usr/sbin/NetworkManager

然而,請記住,上述並不是一個正則表達式的示例,它其實是shell路徑名擴展的一個例子。在此處提及,主要是因爲這兩種用法都支持POSIX字符類。


參考文章地址
* http://www.cnblogs.com/China3S/archive/2013/11/30/3451971.html

發佈了33 篇原創文章 · 獲贊 10 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章