WebGL Tutorial
and more

匹配多行文本

撰写时间:2024-02-29

修订时间:2024-02-29

换行的实质

对于下面的这行代码:

const src = `First line\nSecond line\nThird line`;

在终端上打印出来:

console.log(src);

终端显示:

First line Second line Third line

终端将打印为多行文本。这表明,多行文本只不过是在字符串的相应地方插入换行符\n,而终端这个应用以及其他的文本编辑器,均能识别该字符,并将它们显示为换行的效果。

因此,所谓多行文本,只有一个输入源,而该输入源中出现了换行符\n。这是学习正则表达式时考虑这类问题的正确视角。

换行符可以被匹配

换行符\n,如同其他普通字符一样,可以被正则表达式匹配到。

let src = `First line\nSecond line\nThird line`; let re = /\n/g; let result; while ((result = re.exec(src)) !== null) { console.log(result.index); }

终端显示:

10 22

因此,如果我们要匹配第2行及第3行的第一个单词,由于它们均在换行符\n之后,因此可使用:

let src = `First line\nSecond line\nThird line`; let re = /\n(\w+)/g; let result; while ((result = re.exec(src)) !== null) { console.log(result[1]); // Second // Third }

但,如果我们同时还需要匹配第一行的首单词呢?

如果我们仅考虑到是否存在换行符\n,因而编写:

let src = `First line\nSecond line\nThird line`; let re = /\n?(\w+)/g;

则所有的单词都会被匹配到。因为像line这样的单词,虽然其前面是个空格,但却可匹配前面没有换行符的特征,因此也被匹配出来了。

应使用^元字符来匹配一行之首,因此代码应改为:

let src = `First line\nSecond line\nThird line`; let re = /^\w+|(?:\n(\w+))/g; // ["First", undefined] // ["↵Second", "Second"] // ["↵Third", "Third"]

对于上面的结果,还需额外判断数组位于第1个索引值的元素是否为undefined

感觉真累。

m: 多行标志

RegExpm标志可救赎此问题。它将带有\n换行符的输入源视为多行文本,然后元字符^可匹配到多行中的首字符。

let src = `First line\nSecond line\nThird line`; let re = /^\w+/gm; let result; while ((result = re.exec(src)) !== null) { console.log(result[0]); }

终端输出:

First Second Third

从本质上来讲,计算机只看见了一行的输入源,尽管它之间夹有换行符。但它最终屈从了人类的淫威,只好假装看见了多行。这才有了与人类一样期待的结果。

s: dotAll标志

现在,我们要匹配:字符e, 然后是任意字符,然后是字符S。编写以下代码:

let src = `First line\nSecond line`; let re = /e.S/; let result = re.exec(src); console.log(result); // null

尽管输入源中有e\nS的文本,但上面我们试图使用.来匹配es之间的任意字符,则会匹配失败。因为默认情况下,匹配任意字符的元字符.不会匹配换行符\n

打开RegExps标志,正则表达式引擎的元字符.就可以匹配换行符\n

let src = `First line\nSecond line`; let re = /e.S/s; console.dir(re);

终端输出:

/e.s/S: dotAll: true flags: "s" source: "e.S" ...

redotAll属性值因设置了s标志而被赋值为true

dotAll表示:dot is for all now,意思是,元字符.现在可以真正匹配任意字符了,包括换行符\n

现在,开始匹配:

let src = `First line\nSecond line`; let re = /e.S/s; let result = re.exec(src); console.log(result); // ["e↵S"]

匹配成功。

参考资源

  1. ECMA 262: RegExp Objects
  2. MDN: Regular expressions