什么是正在表達式
正則表達式(regular expression)描述了一種字符串匹配的模式(pattern),可以用來檢查一個串是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串等。
正則表達式快速入門可參考:https://www.w3cschool.cn/regex_rmjc/。正則表達式里包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為"元字符")。簡單的基礎不用多講,講幾個正則中重要又稍微難懂的概念。
1、回溯
正則引擎主要可以分為基本不同的兩大類:一種是DFA(確定性有窮自動機),另一種是NFA(非確定性有窮自動機)。在NFA中由於表達式主導的串行匹配方式,所以用到了回溯(backtracking),這個是NFA最重要的部分,每一次某個分支的匹配失敗都會導-致一次回溯。
回溯法也稱試探法,它的基本思想是:從問題的某一種狀態(初始狀態)出發,搜索從這種狀態出發所能達到的所有“狀態”,當一條路走到“盡頭”的時候(不能再前進),再后退一步或若干步,從另一種可能“狀態”出發,繼續搜索,直到所有的“路徑”(狀態)都試探過。這種不斷“前進”、不斷“回溯”尋找解的方法,就稱作“回溯法”。
舉個例子更能直觀說明。正則是 /ab{1,3}c/ ,其可視化形式是:
而當目標字符串是"abbbc"時,就沒有所謂的“回溯”。其匹配過程是:
如果目標字符串是"abbc",中間就有回溯。
2、貪婪匹配和非貪婪匹配
當正則表達式中包含能接受重復的限定符時,通常的行為是(在使整個表達式能得到匹配的前提下)匹配盡可能多的字符。以這個表達式為例: a.*b ,它將會匹配最長的以a開始,以b結束的字符串。如果用它來搜索 aabab 的話,它會匹配整個字符串 aabab。這被稱為貪婪匹配。
非貪婪匹配就是盡可能少的匹配。一下幾個是非貪婪匹配常見的用法。
以 a.*?b 為例,用它來搜索 aabab 的話,他它會匹配 aab(第一到第三個字符)和 ab(第四到第五個字符)
3、捕獲和斷言
捕獲:當我們使用小括號指定一個子表達式之后,就要對這個子表達式的文本進行匹配,即此分組捕獲的內容,可以在表達式或其它程序中作進一步的處理。一般情況下,每個分組都會自動擁有一個組號,它的規則是:從左到右以分組的左括號作為標志,把第一次出現的分組的組號定為1,第二個即2,以此類推下去。
后向引用:用於重復搜索前面某個分組匹配的文本。例如,\1代表分組1匹配的文本。我們根據示例來深刻理解: \b(\w+)\b\s+\1\b 可以用來匹配重復的單詞,像go go。
非捕獲組:第三個 (?:exp) 不會改變正則表達式的處理方式,只是這樣的組匹配的內容不會像前兩種那樣被捕獲到某個組里面,也不會擁有組號。
零寬斷言:用於查找在某些內容的之前或之后的東西,但是有不包含這些內容本身的時候,零寬斷言就起到作用了。
(?=exp) :也叫零寬度正預測先行斷言,它斷言自身出現的位置的后面能匹配表達式exp。比如 \b\w+(?=ing\b),匹配以ing結尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時,它會匹配sing和danc。
(?<=exp) :也叫零寬度正回顧后發斷言,它斷言自身出現的位置的前面能匹配表達式exp。比如 (?<=\bre)\w+\b 會匹配以re開頭的單詞的后半部分(除了re以外的部分),例如在查找reading a book時,它匹配ading。
正則優化
正則在安全領域中最常見的用途是用來編寫安全策略,比如WAF的攔截策略以及HIDS對應的webshell檢測策略等。以下歸納了幾點正則優化的策略:
a) 合理使用括號
當要捕獲組的時候,使用非捕獲型括號(?:),這是寫策略正則最常用的優化方法,因為使用(?:)可以匹配想要的內容,但不捕獲到組里,可以節省資源,提高效率。
b) 使用非貪婪模式
盡量使用非貪婪模式,因為貪婪模式情況下,容易造成回溯。如果不確定使用哪種模式,優先考慮
c)使用字符組代替分支條件
使用[a-d]表示a~d之間的字母,而不是使用(a|b|c|d)
d) 謹慎用點號元字符,盡可能不用星號和加號這樣的任意量詞
例子: 要匹配 <12345>,其中<>中間是1-5位的數字
正常寫法: <\d*>
優化寫法: <\d{1,5}>
e)提取多選結構開頭的相同字符
例如 the|this 改成th(?:e|is)
f)使用占有優先量詞和固化分組
占有優先量詞:
?+ *+ ++ {m,n}+
占有優先量詞與匹配優先量詞很相似,只是它們從來不會交還已經匹配的字符。
固化分組:
(?>...) ...是指具體內容
固化分組的內容與正常的匹配並無區別,只是當匹配完括號中的內容后,括號中的備用狀態會全部舍去。
g)始、行描點優化
能確定起止位置,使用^能提高匹配的速度。同理,使用$標記結尾,正則引擎則會從符合條件的長度處開始匹配,略過目標字符串中許多可能的字符。在寫正則表達式時,應該將描點獨立出來,例如“^(?:abc|123)”比“^123|^abc”效率高,而“^(abc)”比“(^abc)”效率更高。
其他
正則庫的選擇:
PCRE(Perl Compatible Regular Expressions中文含義:perl語言兼容正則表達式)是一個用C語言編寫的正則表達式函數庫,由菲利普.海澤(Philip Hazel)編寫。PCRE是一個輕量級的函數庫,比Boost之類的正則表達式庫小得多。PCRE十分易用,同時功能也很強大,性能超過了POSIX正則表達式庫和一些經典的正則表達式庫 。
正則測試工具
正則效率評估工具
http://blog.chacuo.net/238.html
url搜集:鏡像流量、日志請求、爬蟲
url去重:布隆過濾器,BerkeleyDB
https://www.anquanke.com/post/id/85298