简易正则表达式教程

 


简介
正则表达式(以下简称“正则式”)在文本匹配等方面是十分有用的。它的好处很难用只字片语说清楚,我们不妨通过一个实例来引入今天的话题。

问题:实现一个函数,判断输入的 email 是否合法。
有一定经验的初学者可以写出下面的代码:

function check_email(src) {
var i = 0;
while ((src[i++] != '@') && (i <= src.length - 1));
if (i == src.length) return(false);
i++;
while ((src[i++] != '.') && (i <= src.length - 1));
if (i == src.length) return(false);
return(true);
}

但他们可能难以想到,如果采用正则式改写此函数,只需要如下的代码:


function check_email(src) {
return(/^.+@.+..+$/.test(src));
}

这看上去很复杂。不要紧,下面的内容,就为读者讲述正则式的语法及应用。

简单的匹配
正则式的主要设计初衷是用作字符串匹配。一个正则式总是包含在两个斜线“/”中。在两个斜线中的字符描述了匹配的信息。最简单的字符是字母和数字。它仅仅匹配其本身。

例如:
/Hello world/ 可以匹配 Hello world 但是不能匹配 Hello world!
/Good morning/ 可以匹配 Good morning 但是不能匹配 Good evening

除此之外,还可以使用记号“.”(点),它匹配除换行外的任意一个字符。

例如:
/./ 可以匹配 a 但是不能匹配 aa
/abc.f/ 可以匹配 abcdf、abcef 但是不能匹配 abcf

另外还有两个非常常用的记号,即“*”(星号)和“+”(加号)。“*”表示匹配前面一个记号零次或多次,而“+”表示匹配前面一个记号一次或多次。

例如:
/abc.*xy/ 可以匹配 abcdexy 也可以匹配 abcxy
/abc.+xy/ 可以匹配 abcdexy 但是不能匹配 abcxy

获取匹配串与非获取式匹配
在正则式匹配成功之后,我们常常需要获得匹配得到的字符串并进行处理。正则式的功能也在这里得到最大体现。
在正则式中,我们使用“(”和“)”(括号)记号来获取匹配串。匹配串从 $1 开始,根据出现在正则式中的顺序依次编号。$0 总表示被正则式匹配的字符串。

例如:
使用 /c(.+?)a(.+?)/ 来匹配 acbbacc
结果:
$0="cbbac"
$1="bb"
$2="c"

非获取式匹配,即采用“(”和“)”来进行匹配,但不获取匹配串的一种方式。这主要是为了利用“(”和“)”的一个功能,即将一大串匹配记号当作一个匹配记号。非获取式匹配通过使用“(?:...)”记号描述。

例如:

/<table>(?:<tr>(?:<td>(.+?)</td>)+?</tr>)+?</table>/

用这个正则式就可以匹配一个 <table> 标记并获取所有 <td> 单元格内的值了。

贪婪匹配和非贪婪匹配
贪婪匹配即在遇到诸如“.+”一类的记号时尽量多匹配字符。

例如:
在串 acbdeb 中,
/a.+b/ 匹配 acbdeb 而非仅仅是 acb

非贪婪匹配即尽量少匹配字符。正则式默认的匹配是贪婪匹配。
要强制进行非贪婪匹配,在需要进行非贪婪匹配的记号后使用记号“?”(问号)。

例如:
在串 abcdeb 中,
/a.+?b/ 匹配 acb 而非 acbdeb

匹配记号表
下表列出了正则式常用的匹配记号。要获取完整的记号表,请查阅相关文档。

记号 说明
/xXX 匹配 HEX ASCII 为 XX 的字符
/cx 匹配由x指明的控制字符。例如,/cM 匹配一个 Control-M 或回车符。x 的值必|须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
/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。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 /^。
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '/n' 或 '/r'。要匹配 $ 字符本身,请使用 /$。
(x) 标记一个用于获取匹配的子表达式 x 的开始和结束位置。子表达式 x 可以获取供以后使用。要匹配这些字符,请使用 /( 和 /)。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 /*。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 /+。
. 匹配除换行符 n 之外的任何单字符。要匹配 .,请使用 /。
[x] 匹配记号串 x 中的任意一个记号,要匹配这些字符,请使用 /[ 和 /]。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪记号。要匹配 ? 字符,请使用 /?。
/ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如,'n' 匹配字符 'n'。'/n' 匹配换行符。序列 '//' 匹配 "/",而 '/(' 则匹配 "("。
| 指明两项之间的一个选择。要匹配 |,请使用 /|。
{n} n 是一个非负整数。匹配前面的子表达式 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配前面的子表达式 n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配前面的子表达式 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。

在 JavaScript 语言中应用正则式
在 JavaScript 语言中运用正则式,几乎甚至比其他任何语言运用正则式都要方便。
我们知道,String 对象有方法

String.replace(src, dst)
它用 dst 来替换字符串中的所有 src。这里的 src 既可以是一个字符串,也可以是一个正则式。例如下面的语法:

a = a.replace(/.+?@.+..+/g, '<a href="mailto: $0">$0</a>');
它把一个串中的所有 e-mail 地址全部转换为链接的形式。
需要注意的是正则式后的 g,它表示匹配所有满足正则式的串(如果没有它,那么整个匹配即替换过程只进行一次)。
单单从这些,体现不出 JavaScript 使用正则式的优越性。读者可能会说,我在其他任何语言(只要它支持正则式匹配)中都可以使用这样的语法。别忘了,JavaScript 中的函数也只当作一种数据类型来使用,请看下面的代码(“i”表示匹配不区分大小写):


a = a.replace(/problems(d+?)s/ig, function($0, $1) { rs = conn.Execute("SELECT * FROM [Problems] WHERE ProblemId=" + $1); ...... });


这段代码的用处不必再说明了吧。虽然用其他语言也可以通过一些函数取回匹配串再进行操作,但显然不如 JavaScript 方便(有些功能甚至用其他语言根本无法实现)。


结束语
这篇教程介绍了正则式的语法与用途,以及使用 JavaScript 进行正则式编程的一点提示。我们看到,使用正则式来匹配或替换字符串,要比以往采用任何方法更加方便和快捷。我们可以使用 JavaScript 和正则式在一起制作出很多有用的 Web 程序。就像人们很喜欢用的论坛 UBB 代码转 HTML 代码的程序一样。
虽然起初这一技术看起来非常复杂,但现在读者已经了解了它的语法。要熟练使用它,只需要花些时间做一点项目了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值