文档章节

newLISP 正则表达式简介

沙枣
 沙枣
发布于 2014/06/11 02:03
字数 2842
阅读 83
收藏 2

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 } "\r\n\x0b\f\r\x85" 14)
nil
> (find { \R } "\r\n\x0b\f\r\x85 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    空白字符,[\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

表达式分组

分组表达式是用括号包围的部分,可以嵌套,它的作用有:

  1. 重新界定了分支的范围。例如:

    cat(aract|erpillar|)

将匹配 "cat", "cataract", 或 "caterpillar". 如果没有分组标记,这个表达式 会匹配 "cataract", "erpillar" 或一个空字符串。

  1. 它同时定义了一个可以捕获的分组表达式。意思是说,当进行匹配时,匹配到 分组表达式的字符串将被保存起来。在 newLISP 中,$1, $2, $3 等内部变量将 会保存分组表达式匹配到的字符串片段。

例如,如果字符串 "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 个分组.

命名捕获 -- 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.

© 著作权归作者所有

上一篇: Io 语言入门
下一篇: newLISP 初级教程
沙枣
粉丝 23
博文 103
码字总数 72499
作品 0
深圳
后端工程师
私信 提问
newLISP你也行 --- newLISP简介

############################################################################# # Name:newLISP你也行 --- newLISP简介 # Author:黄登(winger) # Gtalk:free.winger@gmail.com # Gtalk-Gr......

天国之翼
2012/05/31
1K
0
newLISP 是如何令我惊愕忘形的

译者:skydark 偶然看到这篇文章, 感到非常有意思,忍不住想翻译一下。 原文标题是“How newLISP Took My Breath (And Syntax) Away”,非常漂亮的一个标题,但是不知道怎么翻译好,就随便编...

天国之翼
2012/07/25
7.6K
7
newLISP 10.7.4 发布,易学易用版类 LISP 语言

newLISP 10.7.4 发布了,此版本与 10.7.x 系列兼容。newLISP 是一个友好的、快速且轻量的类似 Lisp 的脚本语言。它具有 LISP 语言的所有功能,但更容易学习和使用。 此次新增特性包括: 当存...

h4cd
2018/09/16
748
2
newLISP 10.6.3 开发版发布,功能更新和 BUG 修复

newLISP 10.6.3 发布,此版本是开发版本,包括一些新特性和改进: 组件和改进 dolist now also accepts arrays. The net-eval function now returns the evaluation of the last function pa......

oschina
2015/07/13
1K
4
newLISP你也行 --- 基础知识

############################################################################# # Name:newLISP你也行 --- 基础知识 # Author:黄登(winger) # Project:http://code.google.com/p/newlisp......

天国之翼
2012/05/31
710
0

没有更多内容

加载失败,请刷新页面

加载更多

CSS3

一.复杂选择器 1.兄弟选择器 具备相同父级元素的平级元素之间称为兄弟元素 注意:兄弟选择器,只能往后,不能往前找 (1).相邻兄弟选择器,获取紧紧挨着某元素后面的兄弟元素 选择器1+选择器2...

wytao1995
16分钟前
3
0
Jmeter录制

1. 加HTTP(s) Test Script Recorder 2. 在 recorder下面加reocrding controller 3. 在HTTP(s) Test Script Recorder中设置下面几项 4. browser设置proxy, 注意端口要和step3中jmeter中的一致......

Rebecca_Hu
20分钟前
3
0
DIV+CSS忽悠前端小白

在大约两年前,DIV+CSS是一对很诱人的组合,会用DIV+CSS制作网页的人,常常会被人赞以大拇指的,记得06年初的时候,我用 div+css布局的一个纯静态网站还拿了学校网页设计比赛的一个奖。 今天...

前端老手
24分钟前
3
0
Win10子系统 linux(Ubuntu18.04) 安装Docker

1)原文件备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 2)编辑源列表文件 sudo vim /etc/apt/sources.list 3)将原来的列表删除,添加如下内容(中科大镜像源) deb http...

jxldjsn
26分钟前
3
0
Ubuntu16.04安装Qt5.12.2

Ubuntu16.04安装Qt5.12.2 第一步:下载文件 https://download.qt.io/official_releases/qt/5.12/5.12.2/ 第二步:安装依赖库 sudo apt-get install build-essential sudo apt-get install li......

shzwork
31分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部