正则表达式(Regular Expression,或 Regex)是一串字符,我们可以用它来定位和操作字符串中的某些元素。因此,我们可以:
这个概念聚焦于在 JavaScript 中使用正则表达式。如果你想学习如何编写正则表达式,Eloquent JavaScript 也许是个不错的资源。
💡 JavaScript 的正则表达式风格是该语言 ECMA-262 标准的一部分。这意味着你不必担心浏览器特定的兼容性问题。
在 JavaScript 中,正则表达式大多写作 /pattern/modifiers 的形式,其中“pattern”是主体正则,“modifiers”是一系列字符,我们可以加上它们来指定特殊选项(就像超能力一样)。
不过,创建正则表达式有两种方式:
const regex = /[a-z]/;
const regex = new RegExp('[a-z]');
两种情况下,JavaScript 都会用正则创建一个对象。建议默认使用字面量来写不可变的模式。
当正则会变化,或者我们还不知道它是什么(比如来自输入)时,可以使用 RegExp 构造函数。
正则表达式有一些可选的“超能力”,叫做flags,它们能带来额外的功能。这些标志可以单独使用,也可以以任意顺序组合使用,并且是正则表达式的一部分。
常用的标志有:
/g - 全局搜索/i - 忽略大小写/m - 多行搜索来看一个简单的例子:
const re = /home/gi;
const str = 'Home, sweet home.';
str.match(re);
// => ["Home", "home"]
g字符让我们能解析出字符串中所有可能的匹配。没有这个功能,JavaScript 只会提取出第一个Home匹配。
忽略大小写标志/i让我们在查找模式时更加灵活。这样一来,我们要找的内容是大写UPPERCASE还是小写lowercase都无所谓。
使用RegExp构造函数时,添加标志的语法不一样。这种情况下,我们只需把标志作为第二个实参传入。
当正则表达式与 JavaScript 内置函数结合时,我们就有了一些强大的方式来操作字符串、从字符串中获取数据。
test()方法非常适合用来搜索,并判断某个目标值是否存在于给定的字符串中。它会返回一个布尔值,true或false。
match()方法会从给定的字符串中提取正则表达式的匹配,返回一个包含匹配及相关信息的数组。
该用哪一个呢? 如果你想快速检查字符串中是否存在某个值,就用test();如果你需要使用那个值,或者想了解关于匹配的更多信息,就用match()。
test()方法会在一段正则表达式和一个指定字符串之间执行匹配搜索,返回 true 或 false。
const str = 'It is difficult to test if you have a virus';
const result = /virus$/.test(str);
console.log(result);
// => true
好吧,但如果我们想拿到正则表达式搜索的实际值,该怎么办呢?
match()方法不只是返回一个布尔值,而是返回一个有用的数组,数组的内容取决于是否找到匹配。
这样,我们既能搜索,也能提取任意字符串中的信息。例如:
const funnyQuote =
'If you see someone crying, ask if it is because of their haircut.';
const regex1 = /someone/;
const regex2 = /happy/;
funnyQuote.match(regex1);
// => ["someone", index: 3, input: "If you see someone crying, ask if it is because of their haircut.", groups: undefined]
funnyQuote.match(regex2);
// => null
当带有全局搜索标志/g时,该方法不会只返回那一个匹配以及下标、输入等有用信息,而是返回数组中出现的所有匹配:
const funnyQuote =
'If you see someone crying, ask if it is because of their haircut.';
const regex3 = /if/gi;
funnyQuote.match(regex3);
// => ["If", "if"];
JavaScript 中的replace()方法让我们可以在给定的字符串中搜索某个值,并用新的值替换它。
string.replace(searchValue, newValue);
用来搜索替换的模式可以是一个字符串,也可以是一个正则表达式。
let string = 'I like dogs!';
let result = string.replace('dogs', 'cats');
let string = 'I would love to travel to Japan';
let result = string.replace(/Japan/g, 'Hawaii');
此外,我们还可以在替换位置传入一个函数,对每个值做额外的改动。
let text = 'Say hello to the chatbot.';
let result = text.replace(/chatbot|hello/gi, function (word) {
return word.toUpperCase();
});
// => "Say HELLO to the CHATBOT"
💡 总的来说,把正则表达式和
replace()方法结合起来,是一种更动态的替换元素的方式。只用单个字符串可能会受到限制。
JavaScript 中的split()方法展示了用正则表达式使用和操作字符串的另一种方式。
这里,我们用正则来识别某个模式,从而切分给定的字符串,例如str.split(/[,.\s]/)。这个模式会用作separator。
const str = 'hello,user.how are.you';
const result = str.split(/[,.\s]/);
console.log(result);
// => ['hello', 'user', 'how', 'are', 'you']
就性能而言,两者都会创建一个 RegExp 对象。主要区别在于正则被编译的频率:
Regular Expression Literal:在初始的代码解析和编译时编译一次RegExp()语法:每次创建新对象时都会编译使用字面量语法可能是更好的选择,不仅因为性能,还因为简单、易读。更多细节可以看看这个 Stackoverflow 讨论。
RegExp()构造函数时,你还需要转义引号,并把反斜杠双重转义。这会让本就难读、难懂的正则表达式更加难上加难。