newLISP 正则表达式简介
newLISP 正则表达式规范newLISP 的正则表达式接口是从 PCRE 标准函数库中获得的,继承了大部分的 功能,但不是完全相同。 在 newLISP 中表示一个正则表达式的时候,请使用大括号包围的方式,因为用双引号的方式,转义符号表示繁琐,行为也有一些怪异的地方。 (regex {Q$E} "$") --> ("$" 0 1) (regex "Q$E" "$") --> nil (regex "Q$E" "$") --> ("$" 0 1) 支持字节和 utf-8 字符的处理newLISP 支持基于字节和 utf-8 字符的正则表达式处理。只有支持 utf-8 的 newLISP 版本才能处理 utf-8 字符串。 当启动一个 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) 字符和元字符一个正则表达式是一个模式,用于从左到右匹配一个字符串。正则表达式中的大部分字符代表自己,用于匹配字符串中相同的字符。作为一个简单的例子,这个匹配模式: The quick brown fox 将会匹配和它一样的字符串片段: > (regex {The quick brown fox} "get it: The quick brown fox") --> ("The quick brown fox" 8 19) 当不区分大小写选项开启时,匹配的内容将和大小写无关。 > (regex {The quick brown fox} "THE QUICK BROWN FOX" 1) --> ("THE QUICK BROWN FOX" 0 19) 正则表达式的威力来自可选的分支和重复的模式。描述它们需要用到元字符,它们将按照特殊的规则处理,已经不是原本的意思了。 有两套不同的元字符:在正则表达式的方括号 转义字符,有几种用处 ^ 字符串开始的断言 (在多行模式下可以匹配行的开始) $ 字符串结束的断言 (在多行模式下可以匹配性的结束) . 匹配除回车之外的任何字符(默认) [ 开始一个字符类的定义 | 开始一个可选的分支 ( 开始一个子表达式 ) 子表达式结束 ? (? 扩展了 ( 的意思,也表示 0 或 1 的匹配数量 也可以表示最少的匹配 * 0 或更多的匹配数量 + 1 或更多的匹配数量,是贪婪匹配符 { 开始一个 "最少/最多" 的数量界定 在方括号内的模式描述叫 "字符类",字符类中的元字符有: 字符转义 ^ 把类取反,如果在字符类定义的第一个字符 - 定义字符的范围连接符 [ POSIX 字符类定义开始符号 (只有跟随有效的 POSIX 语法) ] 结束一个字符类 下面讲讲每个元字符的用法: 反斜杠(BACKSLASH)在正则表达式中要表示元字符本身,就要用反斜杠来转义它。 (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). newLISP 不支持 R (换行符序列)> (find { R } "rnx0bfrx85" 14) nil > (find { R } "rnx0bfrx85 R" 14) 7 简单断言(Simple assertions)断言描述一个边界,可能是一行的开始或结束,也可能是一个单词的开始或结束。 b 匹配一个单词的边界 B 不是一个单词的边界 A 匹配一个字符串的开始 Z 匹配字符串的末尾,也匹配最后一个回车 z 匹配字符串的末尾 这些用法不能用在一个字符类中。 方括号和字符集一对方括号定义一个字符集。 如 [aeiou] 匹配所有的元音字符,而 [^aeiou] 则匹配元音字符之外的其他所有字符。 POSIX 字符类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 空白字符,[sx{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$)} "dddnabcnfff" 1) --> 3 点扩展模式 (?s:pattern) - 点 (.) 可以匹配任意字符,包括回车符。 (find {(?s:A.*?z)} "helloworld" 1) --> 0 注释模式 (?x:pattern) -- 表达式中的空白将被默认删除,# 号以后到行尾的是注释 通常可以一起用: (find {(?xms: hello # this is comment s+ world) "hello world" 1) --> 1 表达式分组分组表达式是用括号包围的部分,可以嵌套,它的作用有:
将匹配 "cat","cataract",或 "caterpillar". 如果没有分组标记,这个表达式 会匹配 "cataract","erpillar" 或一个空字符串。
例如,如果字符串 "the red king" 被下面的模式匹配过: the ((red|white) (king|queen)) 那么捕获的子字符串有 "red king","red",和 "king",分别被保存在 $1,$3 中。 如果分组括号第一个字符是问号 (?...),那么这个分组不用于捕获,只用于分组: the ((?:red|white) (king|queen)) 这次捕获的子字符串只有 "white queen" 和 "queen",分别被保存在 $1 和 $2 中。 newLISP 最多可以捕获 65535 个分组. 命名捕获 -- newLISP 不支持重复重复定义了一个数量,可以跟在下面的字符后面: 一个字符的字面量 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". 断言 (ASSERTIONS)断言是在匹配过程中,对当前状态的一个测试。并不会让匹配指针发生变化。 b B A Z z ^ $ 都是一个断言描述符。 前瞻断言 Lookahead assertions前瞻断言以 (?= 开始,用于匹配的模式,而 (?! 用于不匹配的模式: w+(?=;) 将匹配一个单词,跟着一个分号,但匹配结果并不包括这个分号: foo(?!bar) 将匹配任何出现 "foo" 但后面没有跟着 "bar" 的情况. 顾后断言 lookbehind向后看的语法是匹配 > (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 支持递归调用捕获值作为函数newLISP 支持反向引用: > (regex {(w+)d+1} "abc123abcd") ("abc123abc" 0 9 "abc" 0 3) 调用外部函数 -- newLISP 不支持参考资料用户手册中的 regex replace find 等函数讲解了一些正则表达式应用的例子。 Last updated: 2014.06.05 Copyright 2014-2015 Michael.Song. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |