本文以《JavaScript高级程序设计》第4版作为基础参考,整理使用JavaScript开发过程中,正则表达式使用相关的知识点。
本文是开发知识点系列第八篇。
- 第一篇:JavaScript开发中变量、常量声明的规矩总结
- 第二篇:JavaScript开发:数据类型知识总结
- 第三篇:JavaScript开发:使用Number数据类型需要注意的问题
- 第四篇:JavaScript开发:操作符在实际开发中的使用总结
- 第五篇:JavaScript开发:流程控制语句在实际开发中的使用总结
- 第六篇:JavaScript开发:函数在实际开发中的使用总结(1)
- 第七篇:JavaScript开发:日期对象在开发中的使用总结
正则表达式虽然不是JavaScript核心知识体系内容,但正则表达式在JavaScript开发中有着非常重要的作用。它是一种强大的文本处理工具,可以用来进行字符串的搜索、替换、匹配和分割等操作
-
表单验证:检查用户输入的电子邮件地址、电话号码、密码强度等是否符合规则。
-
搜索和替换:使用正则表达式来实现一个简单的搜索和替换功能。
-
字符串分割:使用正则表达式来按照逗号和空格来分割用户输入的标签。
-
语法高亮:在开发代码编辑器或者Markdown解析器时,可以使用正则表达式来识别和高亮特定的语法。
-
Web爬虫:在开发Web爬虫时,可以使用正则表达式来解析和提取网页中的信息。
需要注意的是,虽然正则表达式很强大,但也有一些限制。例如,正则表达式不适合用来解析嵌套的结构,例如HTML和JSON。
正则表达式对象没有静态方法,只有原型方法
原型方法介绍
-
test():这个方法返回一个布尔值,表示字符串是否匹配正则表达式的模式
javascriptvar regex = /hello/; console.log(regex.test('hello world')); // 输出:true
这个方法在日常开发中使用最多
-
exec() :这个方法在字符串中执行搜索匹配,返回一个结果数组或
null
。如果正则表达式包含分组,那么返回的数组将包含这些分组捕获的结果javascriptvar regex = /h(e)llo/; console.log(regex.exec('hello world')); // 输出:["hello", "e", index: 0, input: "hello world", groups: undefined]
该方法也多见while循环中使用
javascriptvar text = 'hello1 hello2 hello3'; var regex = /hello\d/g; var match; while ((match = regex.exec(text)) !== null) { console.log('匹配到的字符串:' + match[0]); console.log('匹配开始的位置:' + match.index); console.log('输入的原始字符串:' + match.input); }
while
循环和exec()
方法来查找所有匹配hello\d
模式的子串。每次循环,都会打印出匹配到的字符串、匹配开始的位置,以及输入的原始字符串。当exec()
方法没有找到更多的匹配时,它会返回null
,while
循环就会结束。
需要注意的是,在while
循环中使用exec()
方法,必须确保正则表达式使用了全局匹配模式(g
标志)。否则,exec()
方法总是从字符串的开始位置进行搜索,while
循环可能就会变成无限循环。
-
toString():这个方法返回一个字符串,表示正则表达式的字面量形式
javascriptvar regex = /hello/; console.log(regex.toString()); // 输出:"/hello/"
-
compile():这个方法用于改变并重新编译正则表达式。注意,这个方法已经被废弃,不推荐使用
此外,字符串对象也提供了一些方法,可以与正则表达式一起使用,例如match()
、replace()
、search()
和split()
等。
结合字符串使用方法介绍
-
match() :这个方法用于在字符串中搜索匹配正则表达式的子串。如果找到匹配的子串,那么返回一个包含这些子串的数组;否则返回
null
javascriptvar text = 'hello1 hello2 hello3'; var regex = /hello\d/g; console.log(text.match(regex)); // ["hello1", "hello2", "hello3"]
-
replace():这个方法用于在字符串中替换匹配正则表达式的子串。它返回一个新的字符串,原字符串不会被改变
javascriptvar text = 'hello1 hello2 hello3'; var regex = /hello\d/g; console.log(text.replace(regex, 'world')); // "world world world"
-
search() :这个方法用于在字符串中搜索匹配正则表达式的子串。如果找到匹配的子串,那么返回这个子串的开始位置;否则返回
-1
javascriptvar text = 'hello1 hello2 hello3'; var regex = /hello2/; console.log(text.search(regex)); // 7
-
split():这个方法用于按照正则表达式来分割字符串。它返回一个数组,包含了被分割的子串。
javascriptvar text = 'hello1 hello2 hello3'; var regex = /\s/; console.log(text.split(regex)); // ["hello1", "hello2", "hello3"]
这些方法都不会改变原字符串,而是返回一个新的结果。
ES6扩展
在ES6中,正则表达式有了扩展和改进
-
u修饰符 :ES6新增了
u
(unicode)修饰符,用于正确处理四个字节的UTF-16编码javascriptconsole.log(/^\uD83D/u.test('\uD83D\uDC2A')); // false console.log(/^\uD83D/.test('\uD83D\uDC2A')); // true
-
y修饰符 :ES6新增了
y
(sticky)修饰符,用于"粘连"搜索。当使用y
修饰符时,正则表达式会从上次匹配结束的位置开始新的搜索javascriptvar text = 'hello1 hello2 hello3'; var regex = /hello\d\s?/y; console.log(regex.exec(text)); // ["hello1 ", index: 0, input: "hello1 hello2 hello3", groups: undefined] console.log(regex.exec(text)); // ["hello2 ", index: 7, input: "hello1 hello2 hello3", groups: undefined]
-
RegExp构造函数的改进 :在ES6中,
RegExp
构造函数允许接受正则表达式作为参数,这在之前的版本中是不允许的javascriptvar regex = new RegExp(/abc/ig, 'i'); console.log(regex.flags); // "i"
-
flags属性 :ES6为
RegExp
对象新增了flags
属性,返回正则表达式的修饰符javascriptvar regex = /hello/gi; console.log(regex.flags); // "gi"
-
s修饰符 :在ES2018(也就是ES9)中,新增了
s
(dotAll)修饰符,使得.
可以匹配任意单个字符,包括换行符javascriptconsole.log(/hello.world/s.test('hello\nworld')); // true console.log(/hello.world/.test('hello\nworld')); // false
其它
替换模式
在JavaScript的replace()
方法中,$1
、$2
等是特殊的替换模式,它们表示正则表达式中的分组内容。
当正则表达式中使用圆括号()
创建分组时,匹配的结果会被记住,然后可以在replace()
方法的第二个参数中使用$1
、$2
等来引用这些分组的内容。$1
表示第一个分组,$2
表示第二个分组,以此类推
javascript
var text = 'hello world';
var regex = /(hello) (world)/;
console.log(text.replace(regex, '$2 $1')); // 输出:"world hello"
在这个示例中,正则表达式中创建了两个分组:(hello)
和(world)
。然后在replace()
方法中,使用$2 $1
来交换这两个分组的内容。所以,text.replace(regex, '$2 $1')
的结果是"world hello"
。
需要注意的是,$1
、$2
等只能在字符串形式的替换模式中使用。如果使用一个函数作为replace()
方法的第二个参数,那么需要使用函数的参数来获取分组的内容。
根据变量创建正则表达式
在JavaScript中,可以使用RegExp
构造函数来根据变量创建正则表达式
javascript
var pattern = 'hello';
var flags = 'i';
var regex = new RegExp(pattern, flags);
console.log(regex.test('Hello world')); // 输出:true
需要注意的是,如果模式中包含特殊字符,例如\
、^
、$
、.
、*
、+
、?
、(
、)
、[
、]
、{
、}
、|
等,需要在这些字符前面加上\
来进行转义。例如,想要匹配所有包含"."的字符串,需要使用new RegExp('\\.')
来创建正则表达式,而不是new RegExp('.')
。
正则表达式回溯
正则表达式的回溯是指在进行模式匹配时,如果当前的匹配方式失败,正则表达式会回到前一个字符,尝试其他的匹配方式。这是正则表达式的一种基本机制,用于实现复杂的模式匹配。
过多的回溯会导致性能问题,甚至导致正则表达式"冻结"。这通常发生在使用了量词(例如*
、+
、?
、{n,m}
等)和分组(()
)的复杂正则表达式中
javascript
var regex = /(a+)+b/;
regex.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
如果想避免正则表达式的过度回溯,有以下几种方法
-
使用非捕获分组 :非捕获分组
(?:)
不会保存匹配的结果,因此可以减少回溯的次数。 -
使用惰性量词 :默认情况下,正则表达式的量词(
*
、+
、?
、{n,m}
)是贪婪的,会尽可能多地匹配字符。可以在量词后面加上?
来使其变为惰性的,只匹配尽可能少的字符。 -
避免使用嵌套的量词 :嵌套的量词,例如
(a+)+
,往往会导致大量的回溯。应该尽量避免使用嵌套的量词。 -
使用固定长度的模式:如果可能的话,应该使用固定长度的模式,而不是使用量词。固定长度的模式不会产生回溯。
-
使用原子分组 :原子分组
(?>)
是一种特殊的分组,它一旦匹配成功,就不会再进行回溯。然而,JavaScript的正则表达式并不支持原子分组。可以使用第三方的库,例如XRegExp,来使用原子分组。
需要注意的是,以上的方法只能减少回溯的次数,不能完全避免回溯。在某些情况下,回溯是正则表达式的必要机制,不能避免。
总结一下
- 正则表达式没有静态方法
test()
、exec()
使用的比较多- 正则表达式与字符串结合可以使用的方法有
match()
、replace()
、search()
、split()
- ES6的正则表达式有一些扩展
- 正则表达式替换模式可以用来交换字符串
- 可以使用
RegExp
构造函数来根据变量创建正则表达式 - 多总结常规正则表达式
- 理解正则表达式回溯
本文完。