newLISP 的正則表達式接口是從 PCRE 標準函數庫中得到的,繼承了大部分的 功能,但不是徹底相同。git
在 newLISP 中表示一個正則表達式的時候,請使用大括號包圍的方式,由於用雙引號的方式,轉義符號表示繁瑣,行爲也有一些怪異的地方。正則表達式
(regex {\Q$\E} "$") --> ("$" 0 1) (regex "\Q$\E" "$") --> nil (regex "\\Q$\\E" "$") --> ("$" 0 1)
newLISP 支持基於字節和 utf-8 字符的正則表達式處理。只有支持 utf-8 的 newLISP 版本才能處理 utf-8 字符串。express
當啓動一個 REPL 時,出現包含 UTF-8 提示的版本才支持 utf-8 的字符處理:函數
newLISP v.10.6.0 32-bit on Win32 IPv4/6 UTF-8 libffi, options: newlisp -h > (regex {大象} "大象無形" 2048) ("大象" 0 6) > (regex {大象} "大象無形") ("大象" 0 6)
在 utf-8 版本的 newLISP 中,regex 的默認正則標識是 2048, 而普通版本的默認正則標識是 0.測試
> (regex {[a-z]+} "thanks") ("thanks" 0 6) > (regex {[a-z]+} "thanks" 0) ("thanks" 0 6)
一個正則表達式是一個模式,用於從左到右匹配一個字符串。正則表達式中的大部分字符表明本身,用於匹配字符串中相同的字符。做爲一個簡單的例子,這個匹配模式:ui
The quick brown fox
將會匹配和它同樣的字符串片斷:this
> (regex {The quick brown fox} "get it: The quick brown fox") --> ("The quick brown fox" 8 19)
當不區分大小寫選項開啓時,匹配的內容將和大小寫無關。spa
> (regex {The quick brown fox} "THE QUICK BROWN FOX" 1) --> ("THE QUICK BROWN FOX" 0 19)
正則表達式的威力來自可選的分支和重複的模式。描述它們須要用到元字符,它們將按照特殊的規則處理,已經不是本來的意思了。指針
有兩套不一樣的元字符:在正則表達式的方括號 [...]
之間的部分,還有以外的部分。方括號以外的元字符有:code
\ 轉義字符,有幾種用處 ^ 字符串開始的斷言 (在多行模式下能夠匹配行的開始) $ 字符串結束的斷言 (在多行模式下能夠匹配性的結束) . 匹配除回車以外的任何字符(默認) [ 開始一個字符類的定義 | 開始一個可選的分支 ( 開始一個子表達式 ) 子表達式結束 ? (? 擴展了 ( 的意思,也表示 0 或 1 的匹配數量 也能夠表示最少的匹配 * 0 或更多的匹配數量 + 1 或更多的匹配數量,是貪婪匹配符 { 開始一個 "最少/最多" 的數量界定
在方括號內的模式描述叫 "字符類", 字符類中的元字符有:
\ 字符轉義 ^ 把類取反,若是在字符類定義的第一個字符 - 定義字符的範圍鏈接符 [ POSIX 字符類定義開始符號 (只有跟隨有效的 POSIX 語法) ] 結束一個字符類
下面講講每一個元字符的用法:
在正則表達式中要表示元字符自己,就要用反斜槓來轉義它。
(regex {\(\)\{\}\[\]\*\?\+\.\$\^\|} "(){}[]*?+$^|") --> ("(){}[]*?+.$^|" 0 13)
若是不想寫這麼多反斜槓,有個等價的表示方法:
(regex {\Q(){}[]*?+.$^|\E} "(){}[]*?+.$^|") --> ("(){}[]*?+.$^|" 0 13)
這種寫法在字符類內部也能夠:
(regex {[\Q(){}[]*?+.$^|\E]+} "(){}[]*?+.$^|") --> ("(){}[]*?+.$^|" 0 13)
newLISP 處理正則表達式,首先是按照字符串的規則處理其中的一些轉義字符:
|-----------+---------------------------------------------| | 字符 | 描述 | +===========+=============================================+ | \" | 在字符串內部表示雙引號 | |-----------+---------------------------------------------| | \n | 回車符 (ASCII 10) | |-----------+---------------------------------------------| | \r | 換行符 (ASCII 13) | |-----------+---------------------------------------------| | \b | 退格符 (ASCII 8) | |-----------+---------------------------------------------| | \t | TAB 符 (ASCII 9) | |-----------+---------------------------------------------| | \f | 換頁符 (ASCII 12) | |-----------+---------------------------------------------| | \nnn | 三個數字的八進制的字符 ASCII 值 | | | (nnn 從 000 到 255) | |-----------+---------------------------------------------| | \xnn | 兩個數字的十六進制字符 ASCII 值 | | | (xnn 從 x00 到 xff) | |-----------+---------------------------------------------| | \unnnn | 四個十六進制數字表示的 unicode 字符 | | | four nnnn hexadecimal digits. | | | newLISP 在 UTF8 版本中自動轉化成 UTF8 字符 | |-----------+---------------------------------------------| | \\ | 反斜槓本身 (ASCII 92) | |-----------+---------------------------------------------|
下面的字符類是一些一般使用到的字符類:
\d 任何十進制數字 \D 任何不是十進制的數字字符 \s 任何空白字符 \S 任何不適空白的字符 \w 任何單詞的字符 \W 任何不適單詞的字符
這些字符類有三對,分別表明另一個範圍的補集,若是一個字符匹配其中一個, 那麼就補會再匹配另一個了。
這些字符集在字符類內部和外部都是有效的。
\s 不會匹配 VT 符號(CODE 11). 這和 POSIX 中的 [:space:] 不一樣。\s 匹配的 字符有 HT(9), LF(10), FF(12), CR(13) 和 space(32).
> (find { \R } "\r\n\x0b\f\r\x85" 14) nil > (find { \R } "\r\n\x0b\f\r\x85 R" 14) 7
斷言描述一個邊界,多是一行的開始或結束,也多是一個單詞的開始或結束。
\b 匹配一個單詞的邊界 \B 不是一個單詞的邊界 \A 匹配一個字符串的開始 \Z 匹配字符串的末尾,也匹配最後一個回車 \z 匹配字符串的末尾
這些用法不能用在一個字符類中。
一對方括號定義一個字符集。
如 [aeiou] 匹配全部的元音字符,而 [^aeiou] 則匹配元音字符以外的其餘全部字符。
newLISP 支持 POSIX 的字符類:
[01[:alpha:]%]
匹配 "0", "1", 任意字母, 或 "%". 支持的有:
alnum letters and digits alpha letters ascii character codes 0 - 127 blank space or tab only cntrl control characters digit 十進制字符,和 \d 相同 graph printing characters, excluding space lower 小寫字符 print 打印字符,包括空格 punct 打印字符,包括數字和字母 space 空白字符,[\s\x{0b}] upper 大寫單詞 word 單詞字符,和 \w 相同 xdigit 十六進制數字
POSIX 字符集能夠取反:
[12[:^digit:]]
在 UTF-8 模式下,POSIX 字符集並不會匹配超過 128 的字符。
垂直分割符定義了兩個分支:
gilbert|sullivan
這個表達式既能夠匹配 "gilbert" 也能夠匹配 "sullivan". 分支能夠有許多,分支的內容能夠爲空。
word1 | word2 | word3 | word4
大小寫不敏感 (?i:pattern) -- 大寫字母和小寫字母是同樣的:
(find {(?i:pattern)} "PATTERN") --> 0
多行模式 (?m:pattern) -- ^ 只是匹配行首,而 $ 只匹配行尾
(find {(?m:^abc$)} "ddd\nabc\nfff" 1) --> 3
點擴展模式 (?s:pattern) - 點 (.) 能夠匹配任意字符,包括回車符。
(find {(?s:\A.*?\z)} "hello\world" 1) --> 0
註釋模式 (?x:pattern) -- 表達式中的空白將被默認刪除,# 號之後到行尾的是註釋
一般能夠一塊兒用:
(find {(?xms: hello # this is comment \s+ world) "hello world" 1) --> 1
分組表達式是用括號包圍的部分,能夠嵌套,它的做用有:
從新界定了分支的範圍。例如:
cat(aract|erpillar|)
將匹配 "cat", "cataract", 或 "caterpillar". 若是沒有分組標記,這個表達式 會匹配 "cataract", "erpillar" 或一個空字符串。
例如,若是字符串 "the red king" 被下面的模式匹配過:
the ((red|white) (king|queen))
那麼捕獲的子字符串有 "red king", "red", 和 "king", 分別被保存在 $1, $2, $3 中。
若是分組括號第一個字符是問號 (?...), 那麼這個分組不用於捕獲,只用於分組:
the ((?:red|white) (king|queen))
此次捕獲的子字符串只有 "white queen" 和 "queen", 分別被保存在 $1 和 $2 中。 newLISP 最多能夠捕獲 65535 個分組.
重複定義了一個數量,能夠跟在下面的字符後面:
一個字符的字面量 abc 點 . 字符類 反向引用 分組表達式 (除非是個斷言)
一般的重複數量包括一個最小值和一個最大值,用大括號包圍在一塊兒,用逗號分隔。 最大的數值不能大於 65536,並且第一個數字必須比第二個要小:
z{2,4}
會匹配 "zz", "zzz", 和 "zzzz". 右大括號自己不是特殊字符,除非先看到左大括號。 若是第二個數字沒有,但逗號有的話,那麼就沒有最大的限制。若是逗號和最大值都忽略了, 那麼就是一個固定的數量限制。
[aeiou]{3,}
這個模式匹配至少 3 個字母,但最多能夠匹配許多許多,而:
\d{8}
只匹配正好 8 個數字。缺乏最小值的數量限制標記是不合法的。就好象:
\w{,10}
這只是能匹配自身的普通字符而已。
爲方便起見,有三個數量限定符設置了簡寫形式:
* 等價於 {0,} + 等價於 {1,} ? 等價於 {0,1}
一般,數量限定符都是 "貪婪的", 意思是說,他們會盡可能匹配最多的字符,直到 再也匹配不到東西。
若是,一個數量限制標記後面跟一個問號,那麼這個表達式就會變得再也不 "貪婪「, 它將盡可能捕獲儘量少的字符,只要知足條件就能夠了。
/\*.*?\*/
這是 C 語言註釋的模式。它一般是能夠正常工做的。
分組捕獲的結果,不但在系統變量中保存,在正則表達式中一樣能夠調用:
(sens|respons)e and \1ibility
將會匹配 "sense and sensibility" 和 "response and responsibility", 而不是 "sense and responsibility".
斷言是在匹配過程當中,對當前狀態的一個測試。並不會讓匹配指針發生變化。
\b \B \A \Z \z ^ $
都是一個斷言描述符。
前瞻斷言以 (?= 開始,用於匹配的模式,而 (?! 用於不匹配的模式:
\w+(?=;)
將匹配一個單詞,跟着一個分號,但匹配結果並不包括這個分號:
foo(?!bar)
將匹配任何出現 "foo" 但後面沒有跟着 "bar" 的狀況.
向後看的語法是匹配 (?\<=
和 不匹配(?\<\!
:
> (regex {(?<=[a-z]+)\d+} "..123ab456") ("456" 7 3) ;; 前面匹配的模式不能有不定的數量匹配符號 >(regex {(?<=[a-z]+)\d+} "..123ab456") ERR: regular expression in function regex : "offset 10 lookbehind assertion is not fixed length" > (regex {(?<=[a-z][a-z])\d+} "..123ab456") ("456" 7 3) > (regex {(?<![a-z])\d+} "..123ab456") ("123" 2 3) > (regex {(?<![a-b]|[c-d])\d+} "..123ab456") ("123" 2 3) > (regex {(?<![a-b]|[c-d][e-f])\d+} "..123ab456") ("123" 2 3) > (regex {ab(?=[0-9])} "abcdab12") ("ab" 4 2)
newLISP 支持在正則表達式內插入註釋,這讓表達式更具可讀性:
> (regex {(?#this is comment)ab} "ab") ("ab" 0 2)
newLISP 支持反向引用:
> (regex {(\w+)\d+\1} "abc123abcd") ("abc123abc" 0 9 "abc" 0 3)
用戶手冊中的 regex replace find 等函數講解了一些正則表達式應用的例子。
Last updated: 2014.06.05 Copyright 2014-2015 Michael.Song.