使用PCRE(Perl Compatible Regular Expressions)组件创建的正则表达式支持库, 兼容Perl,PHP正则语法,可在修正符中添加"j"选项以启用 JavaScript 兼容语法( 注:标准库中的 string.regex 使用 VBS 语法 )
用法与 PHP 大同小异,例如 PHP 中使用正则表达式拆分字符串的代码如下:
$keywords = preg_split ("/[\s,]+/is", "hypertext language,,programming");
var_dump($keywords);
那么用 aardio 代码用法类似,区别是先创建正则表达式对象,代码如下:
import preg;
import console;
var $keywords = preg("/[\s,]/is").split ( "hypertext language,,programming");
console.varDump( $keywords )
console.pause(true);
preg().replace()
函数用法类似 string.replace()
替换参数可使用字符串(支持逆向引用)、或替换回调函数、替换表对象。
preg().gmath()
全局查找函数类似 string.gmatch()
函数用法。
下面是一个完整的示例:
import console;
import preg;
var regex = preg("(\w+\:\/\/)(?P<host>[\w.]+)");
var testString = /*
http://bbs.aardio.com
http://www.baidu.com
*/
console.log( "测试是否匹配", regex.test(testString) );
console.log( "查找匹配位置", regex.find(testString) );
console.log( "获取匹配字符串", regex.match(testString) );
//全局匹配
for scheme,host in regex.gmatch( testString ) {
console.log("发现匹配字符串", scheme,host )
}
console.log( '字符串替换结果\r\n', regex.replace( testString,"ftp://\2" ) );
console.log( '函数替换结果\r\n', regex.replace( testString
,function(scheme,host){
if( host == "bbs.aardio.com" )
return "ftp://" + host;
} ) );
//数组匹配,找出所有网址并返回数组
var urls = regex.grep( {
"http://bbs.aardio.com";
"www.aardio.net";
"http://www.baidu.com";
} );
console.varDump(urls)
regex.free();
$keywords = preg("/[\s,]/is").split ( "hypertext language,,programming");
console.varDump( $keywords );
console.pause();
注意:
aardio 所有字符串处理函数原生支持模式匹配,aardio 模式匹配是语法简化的正则表达式,基本语法类似正则表达式,但不支持对捕获分组使用模式运算等,添加了更多实用的功能(例如局部禁用模式匹配、元序列等功能),运行速度更快。模式匹配使用!
实现边界断言,而正则表达式使用\b
表示单词分界, aardio提供了更多的字符类,例如\a
表示字母,\u
表示大写字符,\l
表示小写字符, \p
表示标点符号,以及使用冒号表示中文宽字符等等。
aardio 模式匹配式匹配实现了正则表达式最常用的主要功能,但是运行速度却比 preg 正则表达式的速度快数十倍,比 string.regex 提供的 VBS 正则表达式快数百倍。
参考:模式匹配快速入门
如下 aardio 代码用于创建 preg 正则表达式对象
import preg;
var 正则表达式对象 = preg("正则表达式","模式修正符")
注意 aardio 并不推荐将正则表达式放在一对斜杠内 - 这种兼容 PHP 的语法意谓需要多分析一次正则, 所以 preg( "/正则表达式/模式修正符" )
改为 preg("正则表达式","模式修正符")
更好一些。
\
是正则表达式的转义符,因为 aardio 单引号内是转义字符串 - 所以你必须用 '\\'
表示 正则表达式中的 "\"
, 为了避免混淆一般将正则表达式或模式匹配写在双引号中,在 aardio 中双引号包含的是原始字符串。
/pattern/ |
匹配结果 |
---|---|
. |
匹配除换行符以外的所有字符 |
x? |
匹配 0 次或一次 x 字符串 |
x* |
匹配 0 次或多次 x 字符串,但匹配可能的最少次数 |
x+ |
匹配 1 次或多次 x 字符串,但匹配可能的最少次数 |
.* |
匹配 0 次或一次的任何字符 |
.+ |
匹配 1 次或多次的任何字符 |
{m} |
匹配刚好是 m 个 的指定字符串 |
{m,n} |
匹配在 m个 以上 n个 以下 的指定字符串 |
{m,} |
匹配 m个 以上 的指定字符串 |
[] |
匹配符合 [] 内的字符 |
[^] |
匹配不符合 [] 内的字符 |
[0-9] |
匹配所有数字字符 |
[a-z] |
匹配所有小写字母字符 |
[^0-9] |
匹配所有非数字字符 |
[^a-z] |
匹配所有非小写字母字符 |
^ |
匹配字符开头的字符 |
$ |
匹配字符结尾的字符 |
\d |
匹配一个数字的字符,和 [0-9] 语法一样 |
\d+ |
匹配多个数字字符串,和 [0-9]+ 语法一样 |
\D |
非数字,其他同 \d |
\D+ |
非数字,其他同 \d+ |
\w |
英文字母或数字的字符串,和 [a-zA-Z0-9] 语法一样 |
\w+ |
和 [a-zA-Z0-9]+ 语法一样 |
\W |
非英文字母或数字的字符串,和 [^a-zA-Z0-9] 语法一样 |
\W+ |
和 [^a-zA-Z0-9]+ 语法一样 |
\s |
空格,和 [\n\t\r\f] 语法一样 |
\s+ |
和 [\n\t\r\f]+ 一样 |
\S |
非空格,和 [^ \n\t\r\f] 语法一样 |
\S+ |
和 [^ \n\t\r\f]+ 语法一样 |
\b |
匹配以英文字母,数字为边界的字符串 |
\B |
匹配不以英文字母,数值为边界的字符串 |
a|b|c | 匹配符合a字符 或是b字符 或是c字符 的字符串 |
abc |
匹配含有 abc 的字符串 |
(pattern) |
() 这个符号会记住所找寻到的字符串,是一个很实用的语法。第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去。 |
\pattern\i |
i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题。 |
\ |
如果要在 pattern 模式中找寻一个特殊字符,如 * ,则要在这个字符前加上 \ 符号,这样才会让特殊字符失效 |
范例 | 说明 |
---|---|
"/perl/" |
找到含有 perl 的字符串 |
"/^perl/" |
找到开头是 perl 的字符串 |
"/perl$/" |
找到结尾是 perl 的字符串 |
"/c|g|i/" | 找到含有 c 或 g 或 i 的字符串 |
"/cg{2,4}i/" |
找到 c 后面跟着 2个到 4个 g ,再跟着 i 的字符串 |
"/cg{2,}i/" |
找到 c 后面跟着 2个以上 g ,再跟着 i 的字符串 |
"/cg{2}i/" |
找到 c 后面跟着 2个 g,再跟着 i 的字符串 |
"/cg*i/" |
找到 c 后面跟着 0个或多个 g ,再跟着 i 的字符串,如同/cg{0,1}i/ |
"/cg+i/" |
找到 c 后面跟着一个以上 g,再跟着 i 的字符串,如同/cg{1,}i/ |
"/cg?i/" |
找到 c 后面跟着 0个或是 1个 g ,再跟着 i 的字符串,如同/cg{0,1}i/ |
"/c.i/" |
找到 c 后面跟着一个任意字符,再跟着 i 的字符串 |
"/c..i/" |
找到 c 后面跟着二个任意字符,再跟着 i 的字符串 |
"/[cgi]/" |
找到符合有这三个字符任意一个的字符串 |
"/[^cgi]/" |
找到没有这三个字符中任意一个的字符串 |
"/\d/" |
找寻符合数字的字符,可以使用/\d+/ 来表示一个或是多个数字组成的字符串 |
"/\D/" |
找寻符合不是数字的字符,可以使用/\D+/ 来表示一个或是更多个非数字组成的字符串 |
"/\*/" |
找寻符合 * 这个字符,因为 * 在常规表达式中有它的特殊意思,所以要在这个特殊符号前加上\ 符号,这样才会让这个特殊字符失效 |
"/abc/i" |
找寻符合 abc 的字符串而且不考虑这些字符串的大小写 |
所有限定匹配次数的正则量词运算符都是贪婪的。它们尽可能多地匹配更多更长的目标字符串。在正则运算符后添加 ?
能让表达式仅匹配尽可能短的长度。修改器U
也能惰化量词运算符。
下面是一个简单演示:
import console;
import preg;
var str = 'hihihi oops hi';
//使用贪婪的{n,}操作符进行匹配
var m = preg('/((hi){2,})/').match(str); //返回值将是 'hihihi'
console.log(m)
//操作符匹配,在量词运算符后添加问号表示惰化匹配
var m = preg('/((hi){2,}?)/').match(str);//返回值将是 'hihi'
console.log(m)
console.pause()
捕获组引用是在正则表达式内部引用之前捕获到的内容的方法,也可以用于 preg().replace()
函数的替换串中引用匹配分组,使用\0
引用匹配的整个字符串, 使用 \1
引用第一个匹配分组。
使用(?P<name>pattern)
格式的语法指定一个正则捕获组的名称,name 指定组名,pattern 则是正则模式。
请看下面的例子:
import console;
import preg;
var regex = preg("/(?P<quote>""|').*?(?P=quote)/");
var m = regex.exec( ' "测试字符串" ' );
//exec返回的对象,可以使用名字直接引用命名分组
console.log("使用的引号", m.quote )
console.pause()
上式中,quote 就是组名,|
是改组匹配内容的正则。后面的(?P=quote)
是在引用组名为 quote 的捕获组。
\b
匹配单词边界,这是一个零宽匹配,不消耗字符长度
例如 /\bend\b/
只匹配 "end" , 不会匹配 "friend" 或 "ending"。
\B
的作用则完全相反,匹配不是单词边界的位置。
注意:正则表达式又或者 aardio 模式匹配通常都会用大写表示反义。
原子组是一种特殊的正则表达式分组,不会捕获匹配结果。
原子组通常用于提高正则表达式的性能,避免不必要的回溯。可以使用 (?>pattern)
来定义原子组,其中 pattern
是要匹配的模式。
示例:
假设我们有一个字符串 "catastrophe" 并希望匹配 "cat"、"cater" 或 "catastrophe":
/\b(cat|cater|catastrophe)\b/
在这个例子中,正则引擎会首先尝试匹配 "cat"。如果匹配成功,但后续字符不符合整个模式,正则引擎会回溯并尝试匹配 "cater" 和 "catastrophe"。这种回溯会影响性能。
使用原子组可以避免这种情况:
/\b(?>cat|cater|catastrophe)\b/
在这个替代写法中,一旦 "cat" 匹配成功,正则引擎不会回溯去尝试 "cater" 或 "catastrophe",从而提高匹配效率。
递归(Recursion)在正则表达式中用于匹配嵌套结构,例如括号嵌套 (this (that))
或 HTML 标签嵌套 <div><div></div></div>
。我们使用 (?R)
来表示递归调用整个模式。
下面是一个匹配嵌套括号的例子:
\(((?>[^()]+)|(?R))*\)
这个表达式的解释如下:
- \(
和 \)
匹配括号的开头和结尾。
- (?>[^()]+)
匹配不包含括号的所有字符。
- (?R)
递归调用整个模式,匹配嵌套的括号。
- *
表示匹配前面的模式零次或多次。
这个表达式会尽可能多地匹配嵌套的括号。
另一个递归的例子是匹配嵌套的 HTML 标签:
<([\w]+)([^<]*?)>((?>[^<]+)|(?R))*<\/\1>
这个表达式的解释如下:
- <([\w]+)([^<]*?)>
匹配开始标签,并捕获标签名。
- ((?>[^<]+)|(?R))*
匹配标签内容,要么是非标签字符,要么是递归调用整个模式匹配嵌套标签。
- <\/\1>
匹配结束标签,\1
引用之前捕获的标签名。
这个表达式综合运用了字符分组、贪婪操作符、回溯以及递归来匹配嵌套的 HTML 标签。
在处理匹配结果时,有时需要对特定内容进行特别的修改。此时,正则表达式的回调函数就派上用场了。
回调函数用于 preg().replace()
中,实现对匹配结果的动态修改。你可以为 preg().replace()
指定一个函数作为参数,该函数接收匹配结果数组并返回修改后的数组,作为替换的结果。
例如,我们想将某字符串中的首字母转换为大写。
首先,使用正则表达式匹配所有需要大写的字母:
/\b\w/
该表达式使用了单词边界和字符类。接下来,我们需要一个回调函数:
function upperCase(firstLetter) {
return string.upper(firstLetter)
}
函数 upperCase
接收匹配结果数组,并将匹配结果的首字母转换为大写。在这个例子中,firstLetter
代表需要大写的字母。然后,我们利用 preg().replace()
函数实现回调:
import console;
import preg;
function upperCase(c) {
return string.upper(c)
}
var regex = preg("/\b\w/");
var str = regex.replace("very good", upperCase);
console.log(str)
console.pause()
通过这个简单的回调函数,我们就能实现强大的字符串处理功能。
注释在正则表达式中虽然不用于匹配字符串,但却是理解和维护复杂正则表达式的重要工具。随着正则表达式变得越来越复杂,理解其匹配逻辑会变得越来越困难。通过在正则表达式中添加注释,可以减少未来的困惑和误解。
要在正则表达式中添加注释,可以使用 (?#comment)
语法,其中 comment
是你的注释内容。例如:
/(?#匹配数字)\d/
如果你计划将代码公开,添加注释显得尤为重要,这样其他人可以更容易地理解和修改你的代码。注释同样有助于你在将来重新审视自己写的代码时快速理解其逻辑。
此外,可以使用 "x"
或 "(?x)"
修饰符来格式化正则表达式,使其更具可读性。这个修饰符会让正则引擎忽略表达式中的空格和换行符。需要匹配的空格仍然可以通过 \s
或 \
(反斜杠加空格)来表示。
以下是一个使用 "x"
修饰符的示例:
import preg;
import console;
var m = preg("/
\d+ # 匹配数字
\s+ # 匹配空格
\w+ # 匹配单词
/x").match("243523 test");
console.varDump(m);
console.pause();
上述 aardio 代码与以下代码的功能相同:
import preg;
import console;
var m = preg("\d+(?#匹配数字)\s+(?#匹配空格)\w+(?#匹配单词)").match("243523 test");
console.varDump(m);
console.pause();
请始终注意代码的可读性,确保注释清晰明了。
下面列出了当前在 preg
支持库中可能使用的修正符。括号中是这些修正符的内部 PCRE 常量名。修正符中的空格和换行被忽略,其它字符会导致错误。
i
(_PCRE_CASELESS
) 如果设定此修正符,模式中的字符将同时匹配大小写字母。
j
(_PCRE_JAVASCRIPT_COMPAT
) 如果设定此修正符,模式中启用 JavaScript 正则表达式兼容语法。
m
(_PCRE_MULTILINE
) 默认情况下,PCRE 将目标字符串作为单一的一“行”字符所组成的(即使其中包含有换行符)。行起始元字符(^
)仅匹配字符串的起始,行结束元字符($
)仅匹配字符串的结束,或者最后一个字符是换行符时其前面(除非设定了 D
修正符)。这和 Perl 是一样的。当设定了此修正符,行起始和行结束除了匹配整个字符串开头和结束外,还分别匹配其中的换行符的之后和之前。这和 Perl 的 /m
修正符是等效的。如果目标字符串中没有 \n
字符或者模式中没有 ^
或 $
,则设定此修正符没有任何效果。
s
(_PCRE_DOTALL
) 如果设定了此修正符,模式中的圆点元字符(.
)匹配所有的字符,包括换行符。没有此设定的话,则不包括换行符。这和 Perl 的 /s
修正符是等效的。排除字符类例如 [^a]
总是匹配换行符的,无论是否设定了此修正符。
x
(_PCRE_EXTENDED
) 如果设定了此修正符,模式中的空白字符(除了被转义的或在字符类中的)完全被忽略,在未转义的字符类之外的 #
以及下一个换行符之间的所有字符,包括两头,也都被忽略。这和 Perl 的 /x
修正符是等效的,使得可以在复杂的模式中加入注释。然而注意,这仅适用于数据字符。空白字符可能永远不会出现于模式中的特殊字符序列,例如引入条件子模式的序列 (?(
中间。
A
(_PCRE_ANCHORED
) 如果设定了此修正符,模式被强制为“anchored”,即强制仅从目标字符串的开头开始匹配。此效果也可以通过适当的模式本身来实现(在 Perl 中实现的唯一方法)。
D
(_PCRE_DOLLAR_ENDONLY
) 如果设定了此修正符,模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,美元符号也会匹配此字符之前(但不会匹配任何其它换行符之前)。如果设定了 m
修正符则忽略此选项。Perl 中没有与其等价的修正符。
U
(_PCRE_UNGREEDY
) 本修正符反转了匹配数量的值使其不是默认的重复,而变成在后面跟上 ?
才变得重复。这和 Perl 不兼容。也可以通过在模式之中设定 (?U)
修正符或者在数量符之后跟一个问号(如 .*?
)来启用此选项。
X
(_PCRE_EXTRA
) 此修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式中的任何反斜线后面跟上一个没有特殊意义的字母导致一个错误,从而保留此组合以备将来扩充。默认情况下,和 Perl 一样,一个反斜线后面跟一个没有特殊意义的字母被当成该字母本身。当前没有其它特性受此修正符控制。
u
(_PCRE_UTF8
) 此修正符指定启用 UTF-8 编码文本匹配,并且按字符计数(不启用此选项,则使用按字节计数的二进制匹配),开启此选项以后,传入的字符串参数必须使用 UTF-8 编码(aardio 默认就是使用 UTF-8 编码文本字符串)。
preg 扩展库在开启此选项( UTF-8 )以后,正则表达式即按字符计数,并可对中文字符使用匹配修饰符,示例如下:
import preg;
import console;
var regex,err = preg("/中+文/u");
$keywords,j = regex.match ( "abc中中中文" );
console.varDump( $keywords )
console.pause();
启用了 UTF-8 编码以后,也可以使用 Unicode 匹配全部中文,如下:
import preg;
import console;
var regex,err = preg("/[\x{4e00}-\x{9fa5}]+/u");
$keywords,j = regex.match ( "abc中文" );
console.varDump( $keywords )
console.pause();
如果在修正符中指定 "j",则可以使用 Javascript 的正则语法指定 Unicode 编码,如下:
import preg;
import console;
var regex,err = preg("/[\u4e00-\u9fa5]+/ju");
$keywords,j = regex.match ( "abc中文" );
console.varDump( $keywords )
console.pause();
如果是 UTF-8 编码的字符串, 则需要象下面这样匹配中文
import preg;
import console;
var regex,err = preg("/([\x80-\xFF]+)/");