JavaScript正则表达式

正则表达式(Regular Expression)是处理文本信息的强大工具,其应用核心是根据模式(pattern)高效、灵活地匹配文本中的内容,然后,可以对匹配内容进行删除、替换、修改等操作。本文将介绍JavaScript中的正则表达式应用。

正则表达式应用基础

JavaScript正则表达式模式的定义格式为:/<模式>/<修饰符>,定义的模式实际是RegExp类型的对象。其中 ,<模式>的定义稍后会详细介绍,先来看<修饰符>使用,修饰符可以看作正则表达式工作的参数;常用的修饰符包括:

  • 字母g,搜索全部字符串内容。
  • 字母i,忽略字母大小写。
  • 字母u,使用Unicode编码标准搜索,处理中文等字符集时使用。
  • 字母m,多行模式,此时^和$匹配行的开始和结束位置。不使用m修饰符时为单行模式,^字符匹配字符串内容的开始位置,$符号匹配字符串的结束位置。
  • 字符s,默认情况下,圆点(.)匹配除终止符以外的所有字符,指定s修饰符后匹配所有字符。

定义模式中会使用一些有着特殊含义的元字符,就像编程语言中的关键字一样。下面是正则表达式模式中的元字符。

.\+*?[]^$(
){}=!<>|:-

在模式中需要匹配这些字符时,需要使用\字符转义,如\\表示\字符、\.表示圆点等。此外,对于一些特殊的字符,也需要使用\字符转义,与字符串中的转义字符应用类似,如:

转义字符说明
\0NUL
\t水平制表符
\n换行符
\v垂直制表符
\f进纸符
\r回车符
\xNNNN为字符的两位十六进制编码
\uNNNNNNNN为Unicode字符的4位十六进制编码
\u{N}N为Unicode字符的码点(code point)。模式需要使用u修饰符。

RegExp类

创建RegExp对象有两种方法,一是直接使用/符号和修饰符定义的模式,其返回的就是RegExp对象。另一种方法是使用RegExp构造函数,其中,参数一使用字符串定义模式,其中,对于模式中转义字符的\字符需要先进行字符串转义,如"\\d"表示模式中的\d(匹配一个数字);参数二使用字符串指定模式的修饰符,可以是g、i、m、s、u、y、v的组合,如"gi"。

RegExp对象的属性包括:

  • source,只读。获取模式内容,即两/符号之间的内容。
  • flags,只读。获取模式所用的修饰符。
  • global,只读。是否指定了g修饰符。
  • ignoreCase,只读。是否指定了i修饰符。
  • multiline,只读。是否指定了m修改符。
  • dotAll,只读。是否指定了s修饰符。
  • unicode,只读。是否指定了u修饰符。
  • sticky,只读。是否指定了y修饰符。
  • lastIndex,获取或设置下一次搜索的起始位置。

RegExp对象的方法包括:

  • test(s)方法,判断参数s的字符串中是否包含模式内容,包含时返回true,否则返回false。
  • exec(s)方法,返回匹配内容组成的数组,没有匹配内容时返回null。

下面的代码会匹配字符串abc,并且不区分大小写。

JavaScript
<script>
    let p = /abc/gi
    let s = "abc,def,abc,ghi";
    alert(p.test(s));  // true
    alert(p.source); // abc
    alert(p.flags); // gi
    alert(p.global); // true
    alert(p.ignoreCase); // true
    alert(p.unicode); // false
</script>

代码中,首先定义了模式/abc/,即匹配abc字符串,使用g和i修饰符表示搜索全部字符串并忽略字母大不写。变量s定义了一些字符串内容。p.test(s)方法会在s中匹配abc,执行结果会显示true。接下来的几个alert()函数调用显示了p对象的几个只读属性值。

下面的代码演示了exec()方法的应用。

JavaScript
<script>
    let p = /abc/gi
    let s = "abc,def,ABC,ghi";
    while ((m = p.exec(s)) !== null) {
        alert(m);
    }
</script>

本例会显示字符串中的"abc"和"ABC"。

String对象中使用正则表达式

String对象处理字符串时,有一些方法也可以使用正则表达式,下面分别介绍。

match(p)方法,返回所有匹配内容组成的数组,与RegExp对象的exec()方法功能相似;下面的代码演示了相关应用。

JavaScript
<script>
    let p = /abc/gi
    let s = "abc,def,ABC,ghi";
    let arr = s.match(p);
    for (let m of arr) {
        alert(m);
    }
</script>

执行代码会依次显示abc和ABC。

matchAll(p)方法,返回所有匹配内容的迭代器,下面的代码演示了相关应用。

JavaScript
<script>
    let p = /abc/gi
    let s = "abc,def,ABC,ghi";
    for (let m of s.matchAll(p)) {
        alert(m);
    }
</script>

执行代码同样会显示abc和ABC。

search(p),返回第一个匹配内容的索引位置,没有匹配内容时返回-1。下面的代码演示了相关应用。

JavaScript
<script>
    let p = /abc/gi
    let s = "abc,def,ABC,ghi";
    alert(s.search(p)); // 0
    alert(s.search(/xyz/gi)); // -1
</script>

split(p)方法,按照模式分割字符串,返回分割后的数组。可以使用第二个参数指定返回数组的元素数量。下面的代码演示了相关应用。

JavaScript
<script>
    let p = /,/g;
    let s = "abc,def,ghi,jkl";
    let arr1 = s.split(p);
    let arr2 = s.split(p, 3);
    alert(arr1.length); // 4
    alert(arr2.length); // 3
</script>

代码中,定义使用逗号(,)分割字符串。arr1数组保存了全部分分割内容,其元素有4个(使用length属性显示),分别是abc、def、ghi和jkl。arr2数组则保留了前3个分割元素,分别是abc、def和jkl。

replace(p,s)方法,将模式匹配的内容替换为参数s指定的内容。下面的代码演示了相关应用。

JavaScript
<script>
    let p = /abc/gi;
    let s = "abc,def,ABC,jkl";
    alert(s.replace(p, "***")); // ***,def,***,jkl
</script>

本例会将s字符串中的abc和ABC替换为***,显示结果为***,def,***,jkl。

模式

前面已经介绍了如何使用RegExp和String对象操作正则表达式和字符串,下面介绍更多关于模式定义的内容,包括如何定义匹配内容、匹配次数和匹配位置等。

在模式定义中定义匹配的内容时,主要包括以下一些方法:

  • 圆点(.),模式带s修饰符时匹配任意一个字符,否则匹配终止符以外的所有字符。
  • 匹配正则表达式元字符和特殊字符需要使用\符号转义,匹配其它字符直接书写即可。
  • [<字符集>],匹配<字符集>中的任意一个字符。<字符集>中可以是允许字符的列表,如"yn";也可以使用连接号指定范围,如a-z、0-9、A-Z等。如匹配一位十六进制数可以使用/[a-f0-9]/gi。
  • [^<字符集>],匹配<字符集>以外的任意一个字符。如[^abc]会匹配一个abc之外的字符。
  • \d,任意一个数字(0到9)字符。
  • \D,任意一个非数字字符。
  • \s,任意一个空白字符,包括空格、换页符(\f)、换行符(\n)、水平制表符(\t)、垂直制表符(\v)、回车符(\r)。
  • \S,任意一个非空白字符。
  • \w,任意一个单词字符,包括数字、大小写字母和下画线。
  • \W,任意一个非单词字符。
  • 模式中,可以使用一对圆括号定义模式组。
  • 一个位置可以匹配多个模式时可以使用|符号分隔。

除了匹配内容,还可以指定匹配的次数,如:

  • *,匹配0次或多次。*?为非贪婪模式。
  • +,匹配1次或多次。+?为非贪婪模式。
  • ?,匹配0次或1次。??为非贪婪模式。
  • {n},匹配n次。
  • {n,},匹配最少n次。
  • {m,n},匹配m到n次。

常用的位置匹配方法如下:

  • ^符号定义在模式的第一个字符时,表示匹配字符串的开始部分。
  • $符号定义在模式的最后一个字符时,表示匹配字符串的结束部分。
  • \b,表示单词的边界。
  • \B,表示非边界,也\b含义相反。

综合演示

下面的代码演示了如何匹配11位手机号码。

JavaScript
<script>
    let p = /^1\d{10}$/g
    let s = "12345678910";
    alert(p.test(s)); // true
</script>

本例,定义的模式以数字1开始(^1),以10位数字结束(\d{10}$),可以修改字符串s的内容观察执行结果。

下面的代码演示了贪婪模式和非贪婪模式的区别。

JavaScript
<script>
    let p1 = /a+/g;
    let p2 = /a+?/g;
    let s = "aaa";
    alert(p1.exec(s)); // aaa
    alert(p2.exec(s)); // a
</script>

贪婪模式下会尽可能多的匹配内容,如p1模式中可以匹配1个或多个字母a,默认使用贪婪模式,会匹配全部的三个字母a。p2模式使用了非贪婪模式,当它匹配到第一个a时即停止搜索。

下面的代码演示了|运算符和单词边界的匹配。

JavaScript
<script>
    let p = /\b(J|T)\w+\b/gi;
    let s = "Smith John Jerry Frank Tom Timmy";
    let arr = s.match(p);
    for (let m of arr) {
        alert(m);
    }
</script>

本例,模式的含义是以J或T开始的单词,然后最少有一个单词字符,开始和结束的\b表示单词的边界。执行代码会依次显示John、Jerry、Tom和Timmy。此外,(J|T)修改为[JT]也可以有相同的效果。

本文介绍了正则表达式的基础应用,后续文章还会有更多正则表达式和字符串处理的讨论。