JavaScript 正则表达式

Why Regular Expression

  • 复杂的字符串搜寻、替换工作,无法用简单的方式达成
  • 能够帮助你进行各种字符串验证
  • 不止应用于程序语言中:
    • JavaScript, JAVA, Perl, PHP, C#, VB.NET,…
  • 也应用于许多操作系统的主流指令中
    • Linux/UNIX, Mac, Windows PowerScript

语法介绍

1. 定义

正则表达式是一个描述字符模式的对象。

2. 创建方式

    RegExp()构造函数创建和RegExp直接量创建

    var pattern1 = /s$/;

    var pattern2 = new RegExp('s$');

    

    pattern1与pattern2是等价的。

3. 各种表格

3.1 直接量字符

字符 匹配
字母和数字字符 自身
\o NUL字符
\t 制表符(\u0009)
\n 换行符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)
\xnn 由十六进制数nn指定的拉丁字符
\uxxxx 由十六进制数xxxx指定的Unicode字符
\cX 控制字符^X

3.2 字符类

字符 匹配
[...] 方括号内任意字符
[^...] 不在方括号内的任意字符
. 除换行符和Unicode行终止符外的任意字符
\w 任何ASCⅡ字符组成的单词,等价于[a-zA-Z0-9]
\W 任何不是ASCⅡ字符组成的单词,等价于[^a-zA-Z0-9]
\s 任何Unicode空白符
\S 任何非Unicode空白符的字符,注意\w和\S的不同
\d 任何ASCⅡ数字,等价于[0-9]
\D 除了ASCⅡ数字之外的任何字符,等价于[^0-9]
[\b] 退格直接量

3.3 重复字符类

字符 匹配
{n,m} 匹配前一项至少n次,但不能超过m次
{n,m} 匹配前一项n次或多次
{n,m} 匹配前一项n次
? 匹配前一项0次或1次,也就是说前一项是可选的,等价于{0,1}
+ 匹配前一项1次或多次,等价于{1,}
* 匹配前一项0次或多次,等价于{0,}

3.4 选择、分组和引用字符

字符 匹配
| 选择,匹配的是该符号左边的子表达式或右边的子表达式
(...) 组合,将几个项组合为一个单元,这个单元可通过“*”、“+”、“?”和“|”等符号修饰,而且可以记住和这个相匹配的字符串以供伺候的引用使用
(?:...) 只组合,把项组合到一个单元,但不记忆与该组相匹配的字符
\n 和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式(也有可能是嵌套),组索引是从左到右的左括号数,“(?:”形式的分组不编码

3.5 锚字符

字符 匹配
^ 匹配字符串的开头,在多行检索中,匹配一行的开头
$ 匹配字符串的结尾,在多行检索中,匹配一行的结尾
\b 匹配一个单词的边界,简而言之,就是位于字符\w和字符\W之间的位置,或位于字符\w和字符串的开头或结尾之间的位置(但需要注意的是在字符组内[\b]匹配的是退格符)
\B 匹配非单词边界的位置
(?=p) 零宽正向先行断言,要求接下来的字符都与p匹配,但不能包括匹配p的那些字符
(?!p) 零宽负向先行断言,要求接下来的字符不与p匹配

3.6 修饰符

字符 匹配
i 执行不区分大小写的匹配
g 执行一个全局匹配,简而言之,即找到所有的匹配,而不是在找到第一个之后就停止
m 多行匹配模式,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束

用于模式匹配的String方法

方法 意义
String.search() 参数:一个正则表达式。返回:第一个与参数匹配的子串的起始位置,如果找不到,返回-1。不支持全局搜索,如果参数是字符串,会先通过RegExp构造函数转换成正则表达式。
String.replace() 检索和替换。第一个参数:正则表达式,第二个参数:要进行替换的字符串,也可以是函数。设置了g修饰符,则替换所有匹配的子串,否则只替换第一个子串。通过在替换字符串中使用“$n”,可以使用子表达式相匹配的文本来替换字符。
String.match() 参数:一个正则表达式。返回:一个由匹配结果组成的数组。设置g则返回所有匹配结果,否则数组的第一个元素是匹配的字符串,剩下的是圆括号中的子表达式,即a[n]中存放的是$n的内容。
String.split() 参数:正则表达式或字符串。返回:子串组成的数组。

RegExp对象

RegExp构造函数

var pattern = new RegExp(arg1, arg2);

arg1: 正则表达式中两条斜杆之间的文本

arg2: 可选,指定修饰符:g,m,i

RegExp对象

RegExp的属性

属性 意义
source 制度字符串,包含正则表达式的文本。
global 只读布尔值,是否带修饰符g
ignoreCase 只读布尔值,是否带修饰符i
multiline 只读布尔值,是否带修饰符m
lastIndex 可读写整数,如果带g修饰符,这个属性储存在整个字符串中下一次检索开始的位置,这个属性会被exec()和test()方法用到。

RegExp对象

RegExp的方法

方法 意义
exec() 参数:字符串。在一个字符串中执行匹配检索,与String.macth()非全局检索类似,返回一个数组或null。
test() 参数:字符串。返回true or false
toString()

一些栗子

匹配URL

常见的URL:

http://hostname/path.html

当然,.htm或.shtml的结尾也很常见,还包括http或https的协议头。

var patternURL = /https?:\/\/[a-z0-9_.:]+\/[-a-z0-9_:@&?=+,.!/~*%$]*(\.(html|htm|shtml))?/

匹配URL

我们可以将URL分为三个部分:

1、协议头:^http://或^https://

2、主机名:主机名是位于^http://之后和第一个反斜杆(如果有的话)之前的内容。

3、路径:除了上面两者之外的内容。

var patternURL = /^https?:\/\/([^/]+)(/.*)?$/

匹配URL

URL有可能包含端口号,它位于主机名和路径之间,以一个冒号开头:

(:(\d)+)?

var patternURL = /^https?:\/\/([^/:]+)(:(\d)+)?(/.*)?$/

匹配URL

匹配合法的主机名:由点号分隔的部分组成,每个部分可以包括ASCII字符、数字和连字符,但不能以连字符开头和结尾。

var patternHostname = /[a-z0-9]|[a-z0-9][-a-z0-9]*[a-z0-9]/i

结尾的后缀部分只有有限个可能:

(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|[a-z][a-z])

var patternHostname =

/^([a-z0-9]\.|[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\.)(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|[a-z][a-z])$/i

匹配HTML Tag

第一反应:

var pattern = /<[^>]+>/ 

问题:

如果tag中含有“>”,上面的正则就不能正常匹配了。如:

<input name=123 value=">" >

虽然上面这种HTML的写法很少见,但确实合法的。

因此,简单的<[^>]+>就不能用了,需要想个聪明点的办法。

匹配HTML Tag

规律:“<...>”中能够出现

1、引用文本(被单引号或双引号包裹的)

2、非引用形式的“其他文本”(包括除了">"和引号之外的任何字符)

匹配HTML Tag

引用文本:

HTML中的引文可以用双引号,也可以用单引号,但不允许嵌套转义的引号。

可以使用:/("[^"]*"|'[^']*')/ 来匹配

匹配HTML Tag

其他文本:

除了'>'和引号之外的任意字符

可以使用:/[^'">]/ 来匹配

匹配HTML Tag

合体!

var pattern = /<("[^"]*"|'[^']*'|[^'">])*>/

<                # 开始的尖括号"<"
    (            #     任意数量的...
        "[^"]*"  #         双引号字符串
        |        #         或者是...
        '[^']*'  #         单引号字符串
        |        #         或者是...
        [^'">]   #         "其他文本"
    )*           #         
>                # 结束的尖括号">"

匹配String

匹配引文字符串,且容许其中包含转义的引号,例如:

"we have a \"awesome\" world!"

任务步骤:

  1. 匹配起始引号
  2. 匹配正文
  3. 匹配结束引号

不过由于转义之后的引号也能够出现的正文中,所以处理起来比较棘手

匹配String

来看"we have a \"awesome\" world!"的例子

如果有环视可以用:

var pattern = /"([^"]|(?<=\\)")*"/

但它无法正确匹配下面这个无聊的例子:

"/-|-\\" or "[^-^]"

我本来想匹配"/-|-\\"

结果匹配的确是"/-|-\\" or "

匹配String

来看"we have a \"awesome\" world!"的例子

改改改!


因此,我们要匹配的文本其实是开始引号和结束引号之间,包括转义字符和非引号的任何字符。
得到:/"(\\.|[^"])*"/

第一个表达式的问题在于,我们把反斜杆认为只是用来转义引号的,其实反斜杆在字符串中可以用来转义任何字符。

匹配String

来看"we have a \"awesome\" world!"的例子

不过!

因为,这个表达式一开始匹配到了引号之后的文本,如果找不到结束的引号,它就会回溯。
而[^"]匹配到了world\里的反斜杆后,之后的那个引号会被表达式认为是一个结束的引号。。。

上面的表达式还是会错误的匹配:"You need a new\"world\" haha. 中的"You need a new\"world\" 即使这并不是一个字符串

匹配String

来看"we have a \"awesome\" world!"的例子

继续该改改!

所以我们需要保证,字符串里的反斜杆不能以[^"]方式匹配。

[^"]

[^\\"]

匹配String

来看"we have a \"awesome\" world!"的例子

最终版!

/(["'])(((\\.|[^\1\\])*)+)\1/

/^(['"])(((\\['"])?([^\1])*)+)\1/

or

一个简单的语法分析器

TODO

END

JavaScript 正则表达式

By zhulin2609

JavaScript 正则表达式

  • 5,145