《JavaScript忍者秘籍》正则表达式

阅读忍者秘籍。

简介

则表达式是一个拆分字符串并查询相关信息的过程。通常,正则表达式被称为一个模式,是一个用简单的方式描述或者匹配一系列操作符合某个句法规则的字符串。表达式本身包含了允许定义这些模式的术语和操作。大部分时候,相比于硬编码的蛮力验证,正则表达式的实现都更为优雅和易于理解。

基本操作

在 JavaScript 中,有两种方式可以用于创建正则表达式:

  1. 通过正则表达式字面量。

    1
    
    var pattern = /test/;
    
  2. 通过构造 RegExp 对象的实例。

    1
    
    var pattern = new RegExp("test");
    

在开发过程中,如果正则是已知的,则优先选择字面量语法,而第二种则更多的用于动态构建字符串来创建正则表达式。与此同时,除了表达式本身,还有 3 个标志可以用来更详细的描述匹配的操作要求。

  1. i :使得匹配过程不区分大小写。
  2. g :使得所有的实例获得匹配的机会,而不是只匹配第一次出现的结果。
  3. m :使得匹配作用于所有的行。

具体的表达式组成和使用,包括操作符的意义,可以查阅 这个文档

一个具体的例子

编译正则表达式

正则表达式是一个多阶段处理的过程,主要的 2 个阶段是编译执行。编译是发生在正则表达式第一次被创建的时候。而执行则是发生在我们使用编译过的正则表达式进行匹配的时候。通过对稍后要用的正则表达式进行预定义,可以获得明显的速度提升。

一个具体的例子

捕获匹配的片段

正则表达式的实用性表现在捕获已经匹配的结果上,这样方便我们可以进行处理。通过以下 这个例子 ,我们可以看到如何进行简单的非全局的捕获操作。下面的 这个例子 将展示全局捕获非全局捕获的差别。

捕获的引用

  1. 自身匹配:例如使用 \1 来引用表达式中的第一个捕获。
  2. 通过调用 replace() 来替换字符串的时候。如下所示:
1
assert("fontFamily".replace(/([A-Z])/g, "-$1").toLowerCase() == "font-family", "Convert the camelCase into dashed notation.");

小括号有双重责任:不仅要进行分组操作,还可以指定捕获。一般情况下,你可以忽略而不至于产生什么问题,但是如果在正则表达式中有大量的分组,就会引起很多不必要的捕捉。 要让一组括号不进行结果的捕获,我们需要在开始括号后加一个 ?: 标记。

1
2
var pattern = /((ninja-)+)sword/;
var pattern = /((?:ninja-)+)sword/;

实际例子

使用 replace 函数的强大威力来进行字符串的替换。下面是几个实例:

1
"ABCDEfg".replace(/[A-Z]/g, "X")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function upper(all, letter) {
    // 实际上有 4 个参数。
    // 1. 匹配的完整文本 “-b”
    // 2. 匹配的捕获 "b"
    // 3. 匹配字符在源字符串中的索引 6
    // 4. 源字符串
    return letter.toUpperCase();
}

"border-bottom-width".replace(/-(\w)/g, upper);

再来看一个例子:

1
2
3
4
5
6
7
var keys = {};
"foo=1&foo=2&blah=2&foo=3".replace(/([^=&]+)=([^&]*)/g, function (full, key, value){
    keys[key] = (keys[key] ? keys[key] + "," : "") + value;
    return "";
});

console.log(keys);

以上例子表明,使用字符串的 replace() 方法来遍历一个字符串,而不是执行一个实际的搜索替换操作的关键点有两个:

  1. 传递一个函数作为替换值参数。
  2. 该函数并不返回实际的值,只是用于搜索。(利用函数的副作用)

解决一些常见问题

修剪字符串

updatedupdated2023-12-052023-12-05