likes
comments
collection
share

JavaScript开发:正则表达式在开发中的使用总结

作者站长头像
站长
· 阅读数 11

本文以《JavaScript高级程序设计》第4版作为基础参考,整理使用JavaScript开发过程中,正则表达式使用相关的知识点。

本文是开发知识点系列第八篇。

正则表达式虽然不是JavaScript核心知识体系内容,但正则表达式在JavaScript开发中有着非常重要的作用。它是一种强大的文本处理工具,可以用来进行字符串的搜索、替换、匹配和分割等操作

  1. 表单验证:检查用户输入的电子邮件地址、电话号码、密码强度等是否符合规则。

  2. 搜索和替换:使用正则表达式来实现一个简单的搜索和替换功能。

  3. 字符串分割:使用正则表达式来按照逗号和空格来分割用户输入的标签。

  4. 语法高亮:在开发代码编辑器或者Markdown解析器时,可以使用正则表达式来识别和高亮特定的语法。

  5. Web爬虫:在开发Web爬虫时,可以使用正则表达式来解析和提取网页中的信息。

需要注意的是,虽然正则表达式很强大,但也有一些限制。例如,正则表达式不适合用来解析嵌套的结构,例如HTML和JSON。

正则表达式对象没有静态方法,只有原型方法

原型方法介绍

  1. test():这个方法返回一个布尔值,表示字符串是否匹配正则表达式的模式

    var regex = /hello/;
    console.log(regex.test('hello world')); // 输出:true
    

    这个方法在日常开发中使用最多

  2. exec():这个方法在字符串中执行搜索匹配,返回一个结果数组或null。如果正则表达式包含分组,那么返回的数组将包含这些分组捕获的结果

    var regex = /h(e)llo/;
    console.log(regex.exec('hello world')); // 输出:["hello", "e", index: 0, input: "hello world", groups: undefined]
    

    该方法也多见while循环中使用

    var 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()方法没有找到更多的匹配时,它会返回nullwhile循环就会结束。

需要注意的是,在while循环中使用exec()方法,必须确保正则表达式使用了全局匹配模式(g标志)。否则,exec()方法总是从字符串的开始位置进行搜索,while循环可能就会变成无限循环。

  1. toString():这个方法返回一个字符串,表示正则表达式的字面量形式

    var regex = /hello/;
    console.log(regex.toString()); // 输出:"/hello/"
    
  2. compile():这个方法用于改变并重新编译正则表达式。注意,这个方法已经被废弃,不推荐使用

此外,字符串对象也提供了一些方法,可以与正则表达式一起使用,例如match()replace()search()split()等。

结合字符串使用方法介绍

  1. match():这个方法用于在字符串中搜索匹配正则表达式的子串。如果找到匹配的子串,那么返回一个包含这些子串的数组;否则返回null

    var text = 'hello1 hello2 hello3';
    var regex = /hello\d/g;
    console.log(text.match(regex)); // ["hello1", "hello2", "hello3"]
    
  2. replace():这个方法用于在字符串中替换匹配正则表达式的子串。它返回一个新的字符串,原字符串不会被改变

    var text = 'hello1 hello2 hello3';
    var regex = /hello\d/g;
    console.log(text.replace(regex, 'world')); // "world world world"
    
  3. search():这个方法用于在字符串中搜索匹配正则表达式的子串。如果找到匹配的子串,那么返回这个子串的开始位置;否则返回-1

    var text = 'hello1 hello2 hello3';
    var regex = /hello2/;
    console.log(text.search(regex)); // 7
    
  4. split():这个方法用于按照正则表达式来分割字符串。它返回一个数组,包含了被分割的子串。

    var text = 'hello1 hello2 hello3';
    var regex = /\s/;
    console.log(text.split(regex)); // ["hello1", "hello2", "hello3"]
    

    这些方法都不会改变原字符串,而是返回一个新的结果。

ES6扩展

在ES6中,正则表达式有了扩展和改进

  1. u修饰符:ES6新增了u(unicode)修饰符,用于正确处理四个字节的UTF-16编码

    console.log(/^\uD83D/u.test('\uD83D\uDC2A')); // false
    console.log(/^\uD83D/.test('\uD83D\uDC2A')); // true
    
  2. y修饰符:ES6新增了y(sticky)修饰符,用于“粘连”搜索。当使用y修饰符时,正则表达式会从上次匹配结束的位置开始新的搜索

    var 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]
    
  3. RegExp构造函数的改进:在ES6中,RegExp构造函数允许接受正则表达式作为参数,这在之前的版本中是不允许的

    var regex = new RegExp(/abc/ig, 'i');
    console.log(regex.flags); // "i"
    
  4. flags属性:ES6为RegExp对象新增了flags属性,返回正则表达式的修饰符

    var regex = /hello/gi;
    console.log(regex.flags); // "gi"
    
  5. s修饰符:在ES2018(也就是ES9)中,新增了s(dotAll)修饰符,使得.可以匹配任意单个字符,包括换行符

    console.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表示第二个分组,以此类推

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构造函数来根据变量创建正则表达式

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}等)和分组(())的复杂正则表达式中

var regex = /(a+)+b/;
regex.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')

如果想避免正则表达式的过度回溯,有以下几种方法

  1. 使用非捕获分组:非捕获分组(?:)不会保存匹配的结果,因此可以减少回溯的次数。

  2. 使用惰性量词:默认情况下,正则表达式的量词(*+?{n,m})是贪婪的,会尽可能多地匹配字符。可以在量词后面加上?来使其变为惰性的,只匹配尽可能少的字符。

  3. 避免使用嵌套的量词:嵌套的量词,例如(a+)+,往往会导致大量的回溯。应该尽量避免使用嵌套的量词。

  4. 使用固定长度的模式:如果可能的话,应该使用固定长度的模式,而不是使用量词。固定长度的模式不会产生回溯。

  5. 使用原子分组:原子分组(?>)是一种特殊的分组,它一旦匹配成功,就不会再进行回溯。然而,JavaScript的正则表达式并不支持原子分组。可以使用第三方的库,例如XRegExp,来使用原子分组。

需要注意的是,以上的方法只能减少回溯的次数,不能完全避免回溯。在某些情况下,回溯是正则表达式的必要机制,不能避免。

总结一下

  1. 正则表达式没有静态方法
  2. test()exec()使用的比较多
  3. 正则表达式与字符串结合可以使用的方法有match()replace()search()split()
  4. ES6的正则表达式有一些扩展
  5. 正则表达式替换模式可以用来交换字符串
  6. 可以使用RegExp构造函数来根据变量创建正则表达式
  7. 多总结常规正则表达式
  8. 理解正则表达式回溯

本文完。