Dart学习笔记(16):RegExp支持的特性

发表于2018-07-04 17:59 阅读(44)

本文地址:http://www.cndartlang.com/773.html

1、前言

API中对于正则表达式的注释是:
正则表达式的规范和语义与JavaScript相同
详细的规范可以参考:http://ecma-international.org/ecma-262/5.1/#sec-15.1

打开链接,全英文的、、、瞄了一下
不明觉厉!!!

然后,花了一段时间对其支持的特性进行了测试
在附表中将Dart中正则表达式的特性列出来,简单明了
以供大家参考

2、点号通配符

关于Dart中正则表达式支持的特性
越是深入了解,越是感觉复杂

附表中的内容可能不全,但基本上都有提及
这里需要注意其中的 . 点号通配符

通常,点号是不能匹配换行符的
这也使得 .* 表达式变得有些古怪
由于最初Unix正则表达式都是逐行处理的
所以可能后来新的语法是为了保证一致性吧!

但是在测试的时候,结果让人有点头大
例如,处理字符串 ABC\nDEF

import 'dart:io';

void main() {
  String str = "ABC\nDEF";
  RegExp reg = new RegExp(r".*");
  Iterable<Match> matches = reg.allMatches(str);

  for (Match m in matches) {
    print("${m.group(0).isEmpty ?
      "Match is Empty\nIndex is ${m.end}" :
      "Match is ${m.group(0)} \nAscii is ${m.group(0).codeUnits}\nIndex is ${m.end}"}");
    print("--end--\n");
  }
}

运行结果:

Match is ABC 
Ascii is [65, 66, 67]
Index is 3
--end--

Match is Empty
Index is 3
--end--

Match is DEF 
Ascii is [68, 69, 70]
Index is 7
--end--

Match is Empty
Index is 7
--end--

通过分析,对于正则表达式 .*
共匹配有4个Match
分别是:ABC 空 DEF 空
匹配到字符串的 \n 的时候结束
这里 \n 并没有被捕获,而是捕获位置
是不是有点像 $

那么我们来匹配一下 .*$
运行结果:

Match is DEF 
Ascii is [68, 69, 70]
Index is 7
--end--

Match is Empty
Index is 7
--end--

什么意思呢?
在匹配 .* 的时候,如果遇到 \n
处理方式和遇到 $ 一样,停止“本行”匹配
但是不捕获文本、、、有点绕

如果我们打开RegExp的multiLine开关,结果会怎么样?
大家可以动手测试一下

new RegExp(".*", multiLine:true);

对于 .* 表达式,结果没有任何变化
但是对于 .*$ ,结果此时和 .* 的结果一样
也就是说,在打开multiLine开关的时候
如果表达式 .* 遇到 \n ,处理方式和遇到 $ 一样
同时匹配之前的字符串、、、

如果我们想捕获 \n 这个字符串的话,有办法吗?
在测试过后,得出结论
无论是否打开multiLine, .* 都不会匹配 \n 本身
但是,无论是否打开multiLine
[] 字符组和 [^] 排除型字符组都会匹配 \n 本身

可以试一下匹配 [^!]* ,运行结果如下:

Match is ABC
DEF 
Ascii is [65, 66, 67, 10, 68, 69, 70]
Index is 7
--end--

Match is Empty
Index is 7
--end--

\n 的Ascii码是10,结果没有问题
\n 作为文本被捕获,字符串结束的位置也被捕获

如果说的不够清楚,大家可以打开、关闭multiLine开关的情况下
分别测试如下表达式: ^.* 、 .*$ 、 ^.*$ ,然后体会一番

点号通配模式,也有个称呼叫单行模式
在匹配多行文本的时候,需要特别注意
对最终结果还是影响很大的、、、

3、附表:Dart中正则表达式支持的特性

特性
描述
\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。例如,”n”匹配字符”n”。”\n”匹配一个换行符。序列”\\”匹配”\”,”\(“则匹配”(“。
.
匹配任何单个字符。
^
匹配输入字符串的开始位置。如果设置了RegExp 对象的Multiline属性,^也匹配”\n”或”\r”之后的位置。例如,”^.”可以匹配”abc\n123″中的”a”和”1″。
$
匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配 “\n” 或”\r”之前的位置。例如,”.$”可以匹配”abc\n123″中的”c”和”3″。
*
匹配前面的子表达式零次或多次。例如,”zo*”能匹配 “z”或”zoo”整个字符串。”*”等价于{0,}。
+
匹配前面的子表达式一次或多次。例如,”zo+” 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。”+”等价于{1,}。
? (限制符)
匹配前面的子表达式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does”整个字符串。”?”等价于 {0,1}。
?(非贪婪模式)
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串”oooo”,”o+?”将匹配单个”o”,而”o+”将匹配”oooo”。
x|y
匹配x或y。例如,”z|food”能匹配”z”或”food”。”(z|f)ood” 则匹配”zood”或”food”。
[xyz]
字符集合。匹配所包含的任意一个字符。例如,”[abc]” 可以匹配”plain”中的”a”。Dart中不支持字符组嵌套,如:[[a-z]&&[^b]]。
[^xyz]
排除字符集合。匹配未包含的任意字符。例如, “[^abc]” 可以匹配 “plain” 中的”p”。
[a-z]
字符范围。匹配指定范围内的任意字符。例如,”[a-z]”可以匹配”a”到”z”范围内的任意小写字母字符。
[^a-z]
排除字符范围。匹配任何不在指定范围内的任意字符。例如,”[^a-z]”可以匹配任何不在”a”到”z”范围内的任意字符。
{n}
n 是一个非负整数。匹配确定的n次。例如,”o{2}”不能匹配”Bob”中的”o”,但是能匹配”food”中的”oo”。
{n,}
n 是一个非负整数。至少匹配n 次。例如,”o{2,}”不能匹配”Bob”中的”o”,但能匹配”fooood”中的”oooo”。”o{1,}”等价于”o+”。”o{0,}”则等价于”o*”。
{n,m}
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, “o{1,3}” 将匹配 “fooood” 中的”ooo”和”o”。”o{0,1}”等价于”o?”。请注意在逗号和两个数之间不能有空格。
(pattern)
匹配pattern 并获取这一匹配。此时,整个表达式无论多复杂,都被视为一个单元。所获取的匹配可以从产生的 Match对象的group(id) 得到。要匹配圆括号字符,请使用 ‘\(‘ 或 ‘\)’。
(?:pattern)
非匹配型括号。相比普通括号,非匹配型括号只分组不捕获。这样一是可以避免不必要的捕获,提高效率,二是可以让代码可以更加清晰[例如,在捕获字符串中某个名字的时候,可能是group(1)或2、3…使用非匹配型括号,可以仅返回group(1)]。
(?=pattern)
肯定顺序环视。环视匹配的是特定位置,不匹配任何字符,也就是并不会“占用”字符。顺序环视从左到右匹配表达式,如果能匹配,则返回匹配成功信息。
(?!pattern)
否定顺序环视。从左到右匹配表达式,如果不能匹配,则返回匹配成功信息。
(?<=pattern)
肯定逆序环视,不支持。
(?<!pattern)
否定逆序环视,不支持。
(?>pattern)
固化分组,不支持。
(?if then |else)
条件判断,不支持。
(?<name>pattern)
捕获文本到命名组,不支持。
(?#text)
注释,不支持。
\w
匹配包括下划线的任何单词字符。等价于”[A-Za-z0-9_]”。
\W
匹配任何非单词字符。等价于”[^A-Za-z0-9_]”。
\b
匹配单词(\w+)的边界(开始或末尾)。例如,对于字符串”never??!!”,”er\b”可以匹配”er”,”\bne”可以匹配”ne”。
\B
匹配单词(\w+)的非末尾,对于非单词(\W、\W+)字符没有意义。例如,对于字符串”never??!!”,表达式”ev\B”能匹配”ev”;表达式”\?\B”能匹配两个”?”,”\?!\B”能匹配”?!”,此时\B没有意义。
\cx
匹配由x指明的控制字符。例如,\cM匹配Control+M,等价于\r,\cI匹配\t,\cJ匹配\n,。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的”c”字符。
\d
匹配一个数字字符。等价于 [0-9]。
\D
匹配一个非数字字符。等价于 [^0-9]。
\f
匹配一个换页符。等价于 \x0c 和 \cL。
\n
匹配一个换行符。等价于 \x0a 和 \cJ。
\r
匹配一个回车符。等价于 \x0d 和 \cM。
\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S
匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t
匹配一个制表符。等价于 \x09 和 \cI。
\v
匹配一个垂直制表符。等价于 \x0b 和 \cK。
\<
匹配单词开始位置,不支持。
\>
匹配单词结束位置,不支持。
\xn
匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,”\x41″匹配”A”。正则表达式中可以使用ASCII 编码。
\int
反向引用,int为一个正整数。匹配之前获取的、表达式匹配的文本。例如:”(a)(b)(c)\1\2\3″能够匹配”abcabc”。“\”元字符中,优先级为:反向引用>八进制Ascii值>原义字符
\oct
标识一个八进制转义值或一个反向引用。如果之前至少 有otc个获取的子表达式,则otc为后向引用。否则,如果otc为八进制数字 (0-7),则otc为一个八进制转义值(具体查看ASCII 编码)。
\nm
标识一个八进制转义值或一个反向引用。如果 \nm 之前至少有nm个获取得子表达式,则nm为反向引用。如果 \nm之前至少有n个获取,则n为一个后跟文字m的反向引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm(具体查看ASCII 编码)。
\nml
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml(具体查看ASCII 编码)。例如,”\101″能够匹配”A”。
\un
匹配n,其中n是一个用四个十六进制数字表示的 Unicode字符。例如,”\u00A9″匹配版权符号”©”。
[:flag:]
字符簇,如alnum、alpha、digit等,不支持。
\p{flag}
Unicode属性、字母表和区块,如InHanzi、Letter、Number等,不支持。
g、s、i、m、x、U
修饰符,用在正则表达式结尾,不支持。
区分大小写
设置RegExp中可选参数为caseSensitive。
多行匹配
当匹配的字符串是多行的时候,可设置RegExp可选参数multiLine。