ZetCode

JavaScript 正则表达式

最后修改于 2023 年 10 月 18 日

在本文中,我们将展示如何在 JavaScript 中使用正则表达式。

正则表达式用于文本搜索和更高级的文本操作。正则表达式是内置工具,如 grep、sed、文本编辑器(如 vi、Emacs)、编程语言(如 JavaScript、Perl 和 Python)。

正则表达式

在 JavaScript 中,我们使用斜杠 //RegExp 对象来构建正则表达式。

模式 是一个正则表达式,它定义了我们正在搜索或操作的文本。它由文本字面量和元字符组成。元字符是特殊字符,用于控制正则表达式的求值方式。例如,使用 \s,我们搜索空格。

创建模式后,我们可以使用其中一个函数将该模式应用于文本字符串。这些函数包括 testmatchmatchAllsearchreplace

下表显示了一些正则表达式

Regex 含义
. 匹配任何单个字符。
? 匹配前一个元素一次或不匹配。
+ 匹配前一个元素一次或多次。
* 匹配前一个元素零次或多次。
^ 匹配字符串内的起始位置。
$ 匹配字符串内的结束位置。
| 交替运算符。
[abc] 匹配 a、b 或 c。
[a-c] 范围;匹配 a、b 或 c。
[^abc] 否定;匹配除 a、b 或 c 之外的所有字符。
\s 匹配空白字符。
\w 匹配单词字符;等同于 [a-zA-Z_0-9]

test 函数

test 方法执行在正则表达式和指定字符串之间查找匹配项的操作。它返回 true 或 false。

test_fun.js
let words = ['book', 'bookworm', 'Bible',
    'bookish','cookbook', 'bookstore', 'pocketbook'];

let pattern = /book/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

在这个例子中,我们有一个单词数组。模式将在每个单词中查找“book”字符串。

let pattern = /book/;

我们使用斜杠创建模式。正则表达式由四个普通字符组成。

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

我们遍历数组并调用 test 函数。如果模式与单词匹配,它返回 true。

$ node test_fun.js
the book matches
the bookworm matches
the bookish matches
the cookbook matches
the bookstore matches
the pocketbook matches

search 函数

search 函数返回正则表达式和给定字符串之间第一个匹配项的索引。如果未找到匹配项,则返回 -1。

search_fun.js
let text = 'I saw a fox in the wood. The fox had red fur.';

let pattern = /fox/;

let idx = text.search(pattern);
console.log(`the term was found at index: ${idx}`);

在这个例子中,我们找出术语“fox”的第一个匹配项的索引。

$ node search_fun.js
the term was found at index: 8

exec 函数

exec 在指定的字符串中执行查找匹配项的操作。它返回一个包含有关匹配项信息的对象。

exec_fun.js
let words = ['book', 'bookworm', 'Bible',
    'bookish', 'cookbook', 'bookstore', 'pocketbook'];

let pattern = /book/;

words.forEach(word => {

    let res = pattern.exec(word);

    if (res) {
        console.log(`${res} matches ${res.input} at index: ${res.index}`);
    }
});

在这个例子中,我们使用 exec 将模式应用于输入字符串。

if (res) {
    console.log(`${res} matches ${res.input} at index: ${res.index}`);
}

我们打印有关匹配项的信息。它包括匹配项开始的索引。

$ node exec_fun.js
book matches book at index: 0
book matches bookworm at index: 0
book matches bookish at index: 0
book matches cookbook at index: 4
book matches bookstore at index: 0
book matches pocketbook at index: 6

match 函数

match 函数在将模式与输入字符串匹配时检索匹配项。

match_fun.js
let text = 'I saw a fox in the wood. The fox had red fur.';

let pattern = /fox/g;

let found = text.match(pattern);

console.log(`There are ${found.length} matches`);

在这个例子中,我们找出术语“fox”的出现次数。

let pattern = /fox/g;

g 字符是一个标志,用于查找某个术语的所有出现项。通常,搜索在找到第一个出现项时结束。

$ node match_fun.js
There are 2 matches

我们在字符串中找到了两个“fox”术语。

matchAll 函数

matchAll 函数返回一个迭代器,其中包含所有与正则表达式匹配的字符串结果。

matchall_fun.js
let text = 'I saw a fox in the wood. The fox had red fur.';

let rx = /fox/g;
let matches = text.matchAll(rx);

for (let m of matches) {

    console.log(`${m} at ${m.index}`);
}

在这个例子中,我们在字符串中找到所有匹配项;我们还打印它们的索引。

$ node matchall_fun.js 
fox at 8
fox at 29

replace 函数

replace 函数返回一个新字符串,其中某些或所有与模式匹配的内容被替换为替换字符串。

replace_fun.js
let text = 'He has gray hair; gray clouds gathered above us.'

let pattern = /gray/g;

let new_text = text.replace(pattern, 'grey');

console.log(new_text);

在这个例子中,我们从输入字符串创建一个新字符串,其中我们将“gray”单词替换为“grey”。

let pattern = /gray/g;

g 字符是一个标志,用于查找某个术语的所有出现项。

$ node replacing.js
He has grey hair; grey clouds gathered above us.

JS 正则表达式忽略大小写匹配

要启用不区分大小写的搜索,我们使用 i 标志。

case_insensitive.js
let words = ['dog', 'Dog', 'DOG', 'Doggy'];

let pattern = /dog/i;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

在本例中,我们对单词应用模式,而不考虑大小写。

let pattern = /dog/i;

附加 i 标志,我们进行不区分大小写的搜索。

$ node case_insensitive.js
the dog matches
the Dog matches
the DOG matches
the Doggy matches

当进行不区分大小写的搜索时,所有四个单词都与模式匹配。

JS 正则表达式单词边界

元字符 \b 是一个锚点,它匹配一个称为单词边界的位置。它允许搜索整个单词。

word_boundary.js
let text = "This island is beautiful; it is also very large.";

let rx = /\bis\b/g;
var matches = text.matchAll(rx);

for (let m of matches) {

    console.log(`${m} at ${m.index}`);
}

在该示例中,我们查找 is 单词。 我们不想包括 Thisisland 单词。

var matches = text.matchAll(rx);

使用 matchAll,我们找到所有匹配项。

let rx = /\bis\b/g;

使用两个 \b 元字符,我们搜索 is 整个单词。

$ node word_boundary.js 
is at 12
is at 29

JS 正则表达式子模式

子模式是模式中的模式。 子模式使用 () 字符创建。

subpatterns.js
var words = ["book", "bookshelf", "bookworm", "bookcase", "bookish",
    "bookkeeper", "booklet", "bookmark"];

var rx = /^book(worm|mark|keeper)?$/;

for (let word of words) {

    if (word.match(rx)) {
        console.log(`${word} does match`);
    }
    else {
        console.log(`${word} does not match`);
    }
}

该示例创建一个子模式。

var rx = /^book(worm|mark|keeper)?$/;

正则表达式使用一个子模式。 它匹配 bookworm、bookmark、bookkeeper 和 book 单词。

$ node subpatterns.js
book does match
bookshelf does not match
bookworm does match
bookcase does not match
bookish does not match
bookkeeper does match
booklet does not match
bookmark does match

JS 正则表达式点元字符

点 (.) 元字符代表文本中的任何单个字符。

dot_meta.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
    'eleven', 'amen', 'event'];

let pattern = /..even/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

在这个例子中,我们在一个数组中有八个单词。我们对每个单词应用一个包含两个点元字符的模式。

$ node dot_meta.js
the prevent matches
the eleven matches

有两个单词与该模式匹配。

问号元字符

问号 (?) 元字符是一个量词,它匹配前一个元素零次或一次。

question_mark_meta.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
    'eleven', 'amen', 'event'];

let pattern = /.?even/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

在本例中,我们在点字符后添加一个问号。 这意味着在模式中,我们可以有一个任意字符,也可以没有字符。

$ node question_mark_meta.js
the seven matches
the even matches
the prevent matches
the revenge matches
the eleven matches
the event matches

这次,没有前导字符的 even 和 event 单词也匹配。

JS 正则表达式锚点

锚点匹配给定文本中字符的位置。 使用 ^ 锚点时,匹配必须发生在字符串的开头;使用 $ 锚点时,匹配必须发生在字符串的结尾。

anchors.js
let sentences = ['I am looking for Jane.',
    'Jane was walking along the river.',
    'Kate and Jane are close friends.'];

let pattern = /^Jane/;

sentences.forEach(sentence => {

    if (pattern.test(sentence)) {

        console.log(`${sentence}`);
    }
});

在本例中,我们有三个句子。 搜索模式是 ^Jane。 该模式检查“Jane”字符串是否位于文本的开头。 Jane\. 将在句子的末尾查找“Jane”。

JS 正则表达式精确匹配

可以通过将术语置于锚点之间来执行精确匹配:^ 和 $。

exact_match.js
let words = ['seven', 'even', 'prevent', 'revenge', 'maven',
    'eleven', 'amen', 'event']

let pattern = /^even$/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

在这个例子中,我们寻找“even”术语的精确匹配。

$ node exact_match.js
the even matches

JS 正则表达式字符类

字符类定义了一组字符,其中任何一个字符都可能出现在输入字符串中,以便匹配成功。

character_class.js
let words = ['a gray bird', 'grey hair', 'great look'];

let pattern = /gr[ea]y/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`${word}`);
    }
});

在本例中,我们使用字符类来包括 gray 和 grey 单词。

let pattern = /gr[ea]y/;

[ea] 类允许在模式中使用“e”或“a”字符。

命名字符类

有一些预定义的字符类。 \s 匹配一个空白字符 [\t\n\t\f\v]\d 匹配一个数字 [0-9],而 \w 匹配一个单词字符 [a-zA-Z0-9_]

named_character_class.js
let text = 'We met in 2013. She must be now about 27 years old.';

let pattern = /\d+/g;

while ((found = pattern.exec(text)) !== null) {

    console.log(`found ${found} at index ${found.index}`);
}

在这个例子中,我们在文本中搜索数字。

let pattern = /\d+/g;

\d+ 模式查找文本中任意数量的数字集。g 标志使搜索不停止于第一个出现项。

while ((found = pattern.exec(text)) !== null) {

    console.log(`found ${found} at index ${found.index}`);
}

为了找到所有匹配项,我们在 while 循环中使用 exec 函数。

$ node named_character_class.js
found 2013 at index 10
found 27 at index 38

在下面的例子中,我们有一个使用 match 函数的替代方案。

count_numbers.js
let text = 'I met her in 2012. She must be now about 27 years old.'

let pattern = /\d+/g;

var found = text.match(pattern);

console.log(`There are ${found.length} numbers`);

found.forEach((num, i) => {
    console.log(`match ${++i}: ${num}`);
});

为了计算数字,我们使用 \d 命名类。

$ node count_numbers.js
There are 2 numbers
match 1: 2012
match 2: 27

JS 正则表达式统计单词

在下一个例子中,我们计算文本中的单词。

count_words.js
let text = 'The Sun was shining; I went for a walk.';

let pattern = /\w+/g;

let found = text.match(pattern);

console.log(`There are ${found.length} words`);

\w 命名集代表一个单词字符。

let pattern = /\w+/g;

该模式使用量词 (+) 来搜索一个或多个单词字符。全局标志使搜索查找字符串中的所有单词。

console.log(`There are ${found.length} words`);

我们将单词的数量打印到控制台。

$ node count_words.js
There are 9 words

JS 正则表达式交替

交替运算符 | 创建具有多个选择的正则表达式。

alternations.js
let words = ["Jane", "Thomas", "Robert",
    "Lucy", "Beky", "John", "Peter", "Andy"];

let pattern = /Jane|Beky|Robert/;

words.forEach(word => {

    if (pattern.test(word)) {

        console.log(`the ${word} matches`);
    }
});

列表中有八个名称。

let pattern = /Jane|Beky|Robert/;

这个正则表达式查找 "Jane"、"Beky" 或 "Robert" 字符串。

JS 正则表达式捕获组

捕获组是将多个字符视为一个单元的一种方式。它们是通过将字符放置在一组圆括号内创建的。例如,(book) 是一个包含“b”、“o”、“o”、“k”字符的单个组。

捕获组技术允许我们找出与正则表达式模式匹配的字符串的部分。

capturing_groups.js
content = `<p>The <code>Pattern</code> is a compiled
representation of a regular expression.</p>`;

let pattern = /(<\/?[a-z]*>)/g;

let found = content.match(pattern);

found.forEach(tag => {

    console.log(tag);
});

代码示例通过捕获一组字符来打印来自所提供字符串的所有 HTML 标签。

let found = content.match(pattern);

为了找到所有标签,我们使用 match 方法。

$ ./capturing_groups.js
<p>
<code>
</code>
</p>

我们找到了四个 HTML 标签。

JavaScript 正则表达式电子邮件示例

在下面的示例中,我们创建一个 regex 模式来检查电子邮件地址。

emails.js
let emails = ["luke@gmail.com", "andy@yahoocom",
    "34234sdfa#2345", "f344@gmail.com"];

let pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/;

emails.forEach(email => {
    if (pattern.test(email)) {

        console.log(`${email} matches`);
    } else {

        console.log(`${email} does not match`);
    }
})

此示例提供了一种可能的解决方案。

let pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,18}$/;

第一个 ^ 和最后一个 $ 字符提供了一个精确的模式匹配。不允许模式之前和之后的字符。电子邮件分为五个部分。第一部分是本地部分。这通常是公司、个人或昵称的名称。[a-zA-Z0-9._-]+ 列出了我们可以在本地部分中使用的所有可能字符。它们可以被使用一次或多次。

第二部分由字面字符 @ 组成。第三部分是域部分。它通常是电子邮件提供商的域名,例如 yahoo 或 gmail。[a-zA-Z0-9-]+ 是一个字符类,提供可以在域名中使用的所有字符。+ 量词允许使用这些字符中的一个或多个。

第四部分是点字符;它前面是转义字符 (\) 以获取字面点。

最后一部分是顶级域名:[a-zA-Z.]{2,18}。顶级域名可以有 2 到 18 个字符,例如 sk、net、info、travel、cleaning、travelinsurance。最大长度可以是 63 个字符,但今天大多数域名都短于 18 个字符。还有一个点字符。这是因为一些顶级域名有两部分;例如 co.uk。

$ node emails.js
luke@gmail.com matches
andy@yahoocom does not match
34234sdfa#2345 does not match
f344@gmail.com matches

来源

正则表达式 - 语言参考

在本文中,我们介绍了 JavaScript 中的正则表达式。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

查看 所有 JavaScript 教程。