深入浅出:玩转RegEx正则

大家好,我是Ysh

文章结尾配有正则语法大全,可当字典随用随取。

RegEx简介

正则表达式 (英语:Regular Expression,常简写为regex、regexp或RE) 又称为规律表达式``正则表示法规则表达式常规表示法,是计算机科学中的一个概念。正则表达式是一种强大的工具,用于匹配和处理文本。它可以验证用户输入、提取字符串中的数据,或进行复杂的文本操作。掌握正则表达式对开发人员来说是必不可少的。

RegEx历史

正则表达式的历史可以追溯到20世纪50年代,其发展过程如下:

本篇文章将使用JavaScript语言对正则进行讲解

什么是正则表达式

正则表达式是一种定义搜索模式的字符序列,常被简称为"regex"。它提供了一种强大的方式来搜索替换操作文本。正则表达式可以在字符串中查找匹配项,帮助识别特定的文本或字符模式。

定义搜索模式的字符序列 是指通过特定的字符和符号组合来创建一个模式,用于在文本中查找符合该模式的字符串。这个模式可以是简单的字符序列,也可以是包含特殊字符的复杂表达式。正则表达式就是这样一种工具,用于描述和匹配这些字符序列的模式。

在JavaScript中创建正则表达式

1. 使用正则表达式字面量

字面量用斜杠(/)包围,直接定义模式。

javascript 复制代码
const regTest = /pattern/;

示例

javascript 复制代码
const regTest = /ab+c/;//这个模式匹配的字符串必须以一个"a"开头,后面跟着一个或多个"b",并且以一个"c"结尾。

2. 使用RegExp构造函数

使用RegExp构造函数这种方式允许对正则表达式进行运行时编译,并且在模式可能更改时非常有用

javascript 复制代码
const regTest = new RegExp("pattern");

示例

javascript 复制代码
const regTest = new RegExp("ab+c");

无论是使用字面量还是使用构造函数构建,其效果相同,选择哪种取决于你的习惯。

如何编写正则表达式的模式

1. 简单模式

匹配精确的字符序列。

  • 示例 :模式/abc/匹配字符串中的"abc"。

2. 特殊字符

增强模式匹配功能,如重复匹配、特定类型字符匹配等。

  • 示例*表示匹配前一项0次或多次。

    • 模式/ab*c/
    • 匹配"ac", "abc", "abbc"等形式的字符串。

如何在JavaScript中使用正则表达式

在JavaScript中,正则表达式可以通过RegExp对象和String对象的方法进行使用。以下是一些常用方法和具体用法:

定义正则表达式

  1. 字面量表示法

    javascript 复制代码
    const test = /pattern/;
    // 示例
    const test = /ab+c/;
  2. 构造函数表示法

    javascript 复制代码
    const test = new RegExp("pattern");
    // 示例
    const test = new RegExp("ab+c");

常用方法

  1. test() 方法

    • 检查字符串是否与正则表达式匹配。
    javascript 复制代码
    let pattern = /hello/;
    let str = "hello world";
    let result = pattern.test(str);
    console.log(result); // 输出为:true
  2. exec() 方法

    • 搜索字符串中的匹配项,返回一个数组。
    javascript 复制代码
    let pattern = /world/;
    let str = "hello world";
    let result = pattern.exec(str);
    console.log(result); // 输出为:["world", index: 6, input: "hello world"]
  3. match() 方法

    • 搜索字符串中的所有匹配项,返回一个数组。
    javascript 复制代码
    let str = "The cat chased the mouse.";
    let matches = str.match(/the/gi);
    console.log(matches); // 输出为:["The", "the"]
  4. matchAll() 方法

    • 返回所有匹配项的迭代器。
    javascript 复制代码
    let str = "Hello world! This is a test string.";
    let regex = /[a-zA-Z]+/g;
    let matches = str.matchAll(regex);
    for (let match of matches) {
        console.log(match);
    }
    //运行结果
     //[ 'Hello', index: 0, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'world', index: 6, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'This', index: 13, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'is', index: 18, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'a', index: 21, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'test', index: 23, input: 'Hello world! This is a test string.', groups: undefined ]
     //[ 'string', index: 28, input: 'Hello world! This is a test string.', groups: undefined ]
  5. search() 方法

    • 返回匹配项的起始索引。
    javascript 复制代码
    let str = "The cat chased the mouse.";
    let pattern = /mouse/;
    let result = str.search(pattern);
    console.log(result); // 输出为:17
  6. replace() 方法

    • 替换字符串中指定模式的第一个匹配项。g为全局匹配
    javascript 复制代码
    let str = "Hello, World!";
    let newStr = str.replace(/o/g, "0");
    console.log(newStr); // 输出为:"Hell0, W0rld!"
  7. replaceAll() 方法

    • 替换字符串中指定模式的所有匹配项。
    javascript 复制代码
    let str = "apple,banana,apple,grape";
    let newStr = str.replaceAll("apple", "orange");
    console.log(newStr); // 输出为:"orange,banana,orange,grape"
  8. split() 方法

    • 根据正则表达式分隔字符串。
    javascript 复制代码
    let str = "apple,banana,grape";
    let arr = str.split(/,/);
    console.log(arr); // 输出为:["apple", "banana", "grape"]

使用标志进行高级搜索

  1. 忽略标志(i)

    • 忽略大小写。
    javascript 复制代码
    let re = /hello/i;
    let testString = "Hello, World!";
    let result = re.test(testString);
    console.log(result); // 输出为:true
  2. 全局标志(g)

    • 查找所有匹配项。
    javascript 复制代码
    let re = /hi/g;
    let testString = "hi there, hi again!";
    let result = testString.match(re);
    console.log(result); // 输出为:["hi", "hi"]
  3. 组合标志(gi)

    • 全局和忽略大小写。
    javascript 复制代码
    let re = /hi/gi;
    let testString = "Hi there, HI again!";
    let result = testString.match(re);
    console.log(result); // 输出为:["Hi", "HI"]
  4. u标志

    • 处理Unicode字符。
    javascript 复制代码
    // 不使用u标志
    let result1 = 'Smile Please 😊'.match(/[😒😊🙄]/);
    console.log(result1); // 输出为:["�"]
    
    // 使用u标志
    let result2 = 'Smile Please 😊'.match(/[😒😊🙄]/u);
    console.log(result2); // 输出为:["😊"]

正则表达式中的锚点

锚点是正则表达式中的特殊字符,它们不表示实际字符,而是用于检查字符在字符串中是否处于特定的位置。本文将讲解两个主要的锚点:^$

1. 锚点 ^

  • 功能:匹配文本的开头。
  • 用法:检查字符串是否以特定字符或模式开头。

示例

javascript 复制代码
let str = 'Ysh';
console.log(/^S/.test(str)); // 输出为:false

在这个示例中,正则表达式 ^S 检查字符串是否以字符 "S" 开头,因为字符串 "Ysh" 不是以 "S" 开头,所以结果为 false

2. 锚点 $

  • 功能:匹配文本的结尾。
  • 用法:检查字符串是否以特定字符或模式结尾。

示例

javascript 复制代码
let str = 'on';
console.log(/n$/.test(str)); // 输出为:true

在这个示例中,正则表达式 n$ 检查字符串是否以字符 "n" 结尾,因为字符串 "on" 是以 "n" 结尾,所以结果为 true

3. 组合使用 ^$

  • 功能:检查字符串是否完全匹配某个模式。

示例

javascript 复制代码
let isValid = /^\d\d:\d\d$/.test('10:01');
console.log(isValid); // 输出为:true

在这个示例中,正则表达式 ^\d\d:\d\d$ 确保字符串包含两个数字,后跟一个冒号,然后是两个数字。

4. 多行模式中的锚点 ^$

  • 功能:在多行模式下,匹配多行字符串中各行的开头和结尾。
  • 标志m

示例

单行模式(默认):

javascript 复制代码
let str = `1st line
2nd line
3rd line`;

let re = /^\d/g;// "^\d" 匹配字符串开头的数字
//由于单行模式是默认的,因此它只匹配字符串开头的第一个数字 "1"
let matches = str.match(re);

console.log(matches); // 输出为:["1"]

多行模式(m 标志):

javascript 复制代码
let str = `1st line
2nd line
3rd line`;

let re = /^\d/gm;
let matches = str.match(re);

console.log(matches); // 输出为:["1", "2", "3"]

在多行模式下,^$ 会匹配每一行的开头和结尾,适合处理包含多行或换行符的文本。

5. 单词边界 \b

  • 功能:匹配单词的边界,检查单词字符和非单词字符之间的位置。
  • 用法:匹配独立的单词,而不是其子串。

示例

javascript 复制代码
let pattern = /\bword\b/; 
console.log(pattern.test("This is a word.")); // 输出为:true
console.log(pattern.test("This is wording.")); // 输出为:false

在这个示例中,\bword\b 只匹配独立的单词 "word",而不匹配word后面的字符如 "wording"。

其他示例:

  • 匹配整数\b\d+\b匹配字符串中的整数,但不包括数字字符相邻的非数字字符。

    javascript 复制代码
    let pattern = /\b\d+\b/;
    console.log(pattern.test("123")); // 输出为:true
    console.log(pattern.test("123abc")); // 输出为:false
  • 匹配完全由单词 "word" 组成的字符串^\bword\b$

    javascript 复制代码
    let pattern = /^\bword\b$/;
    console.log(pattern.test("word")); // 输出为:true
    console.log(pattern.test("wording")); // 输出为:false

正则表达式中的量词

量词允许你指定在字符串中匹配的字符或字符类的数量。以下是一些常见的量词及其用法。

1. 精确数量量词 {n}

  • 功能:指定字符或字符类的精确数量。
  • 用法x{n}

示例

javascript 复制代码
let str = 'Year: 2022';
let re = /\d{4}/; // 匹配一个四位数字
let result = str.match(re);
console.log(result); // 输出为:["2022"]

2. 区间量词 {n,m}

  • 功能 :匹配字符或字符类的数量在 nm 之间,包括 nm
  • 用法x{n,m}

示例

javascript 复制代码
let str = "The meeting is scheduled for 10:30 AM and ends at 2 PM";
let re = /\d{2,4}/g; // 匹配2到4位数字的数
let result = str.match(re);
console.log(result); // 输出为:[ '10', '30' ]

3. 至少数量量词 {n,}

  • 功能 :匹配字符或字符类至少 n 次。
  • 用法x{n,}

示例

javascript 复制代码
let str = 'The price of the item is $2500';
let re = /\d{2,}/g; // 匹配至少2位数字的数
let result = str.match(re);
console.log(result); // 输出为:["2500"]

4. 简写形式 +, ?, *

  • + :匹配前一个字符或组一次或多次,等同于 {1,}
  • ? :匹配前一个字符或组零次或一次,等同于 {0,1}
  • * :匹配前一个字符或组零次或多次,等同于 {0,}

示例

javascript 复制代码
// 使用 + 匹配一个或多个数字
let phone = "+86-1008611";
let result = phone.match(/\d+/g);
console.log(result); // 输出为:["86", "1008611"]

使用 ? 匹配零次或一次

javascript 复制代码
let str = '天空的 color 是蓝色, 海的 colour 也是蓝色';
let result = str.match(/colou?r/g); // 匹配"color"和"colour"
console.log(result); // 输出为:["color", "colour"]

使用 * 匹配零次或更多

javascript 复制代码
let str = 'Computer 好玩, computational 牛批';
let re = /comput\w*/g; // 匹配"computer"和"computational"
let results = str.match(re);
console.log(results); // 输出为:["computer", "computational"]

5. 贪婪量词

  • 功能:匹配尽可能多的字符。
  • 默认行为:贪婪模式。

示例

javascript 复制代码
let regexp = /".+"/g;
let str = '这个 "Boy" 不太"冷静"';
console.log( str.match(regexp) ); // 输出为:['"Boy\" 不太"冷静"']

6. 非贪婪量词(懒惰模式)

  • 功能:匹配尽可能少的字符。
  • 用法 :在量词后添加 ?

示例

javascript 复制代码
let regexp = /".+?"/g;
let str = '这个 "Boy"才是"杀手"';
console.log( str.match(regexp) ); // 输出为:['"Boy"']

7. 单词边界 \b

  • 功能:匹配单词的边界。
  • 用法:匹配单词的开头或结尾。

示例

javascript 复制代码
let pattern = /\bword\b/;
console.log(pattern.test("This is a word.")); // 输出为:true
console.log(pattern.test("This is wording.")); // 输出为:false

其他示例:

  • 匹配整数\b\d+\b

    javascript 复制代码
    let pattern = /\b\d+\b/;
    console.log(pattern.test("123")); // 输出为:true
    console.log(pattern.test("123abc")); // 输出为:false
  • 匹配完全由单词 "word" 组成的字符串^\bword\b$

    javascript 复制代码
    let pattern = /^\bword\b$/;
    console.log(pattern.test("word")); // 输出为:true
    console.log(pattern.test("wording")); // 输出为:false

正则表达式的集合与区间

在正则表达式中,集合和区间用于匹配特定的字符或一系列字符。以下是详细的解释和示例。

1. 集合

集合使用方括号 [...] 来定义,匹配集合中的任何字符。

示例

  • 匹配字符串中的所有元音字母:
javascript 复制代码
let str = 'The quick brown fox jumps over the lazy dog.';
let re = /[aeiou]/g;
let results = str.match(re);
console.log(results); // 输出为:['e', 'u', 'i', 'o', 'o', 'u', 'o', 'e', 'e', 'a', 'o']
  • 匹配以 'c' 或 'r' 开头,并跟着 'at' 的单词:
javascript 复制代码
let str = 'The cat chased the rats in the backyard';
let re = /[cr]at/g;
let results = str.match(re);
console.log(results); // 输出为:['cat', 'rat']

2. 区间

区间允许你在集合内指定一系列字符,例如 [a-z] 匹配从 'a' 到 'z' 的任何小写字母。

示例

  • 匹配字符串中的所有小写字母:
javascript 复制代码
let str = 'Hello World!';
let re = /[a-z]/g;
let results = str.match(re);
console.log(results); // 输出为:['e', 'l', 'l', 'o', 'o', 'r', 'l', 'd']

3. 否定/排除区间

使用 [^...] 在集合中排除某些字符。

示例

  • 匹配字符串中不是数字的任何字符:
javascript 复制代码
let str = 'The price is $19.99';
let re = /[^0-9]/g;
let results = str.match(re);
console.log(results); // 输出为:['T', 'h', 'e', ' ', 'p', 'r', 'i', 'c', 'e', ' ', 'i', 's', ' ', '$', '.', '.']
  • 匹配任何不是小写字母的字符:
javascript 复制代码
let str = 'The price is $19.99';
let results2 = str.match(/[^a-z]/g);
console.log(results2); // 输出为:['T', ' ', ' ', ' ', '$', '1', '9', '.', '9', '9']

4. 预定义的字符类

1. \d

  • 匹配任何数字字符,等价于 [0-9]

示例

  • 格式化电话号码:
javascript 复制代码
let phone = '+86-10010';
let re = /\d/g;
let numbers = phone.match(re);
let phoneNo = numbers.join('');
console.log(phoneNo); // 输出为:8610010

2. \s

  • 匹配单个空白字符,包括空格、制表符和换行符。

3. \w

  • 匹配任何单词字符(字母数字字符或下划线),等价于 [a-zA-Z0-9_]

示例

  • 匹配单词和数字的组合:
javascript 复制代码
let str = 'O2 is oxygen';
let re = /\w\d/g;
console.log(str.match(re)); // 输出为:["O2"]

5. 反向类

反向类使用大写字母表示,匹配不包含在相应小写类中的字符。

1. \D

  • 匹配非数字字符。

示例

  • 提取电话号码中的数字:
javascript 复制代码
let phone = '+86-1-0-0-8-6-1-1';
let re = /\D/g;
console.log(phone.replace(re, '')); // 输出为:861008611

2. \S

  • 匹配非空白字符。

3. \W

  • 匹配非单词字符。

综合示例

以下是一个综合示例,展示了如何结合这些类和区间进行更复杂的模式匹配:

javascript 复制代码
let str = 'The quick brown fox jumps over the lazy dog 12345.';
let re = /[\d\w\s]/g; // 匹配数字、字母和空白字符
let results = str.match(re);
console.log(results.join('')); // 输出为:'The quick brown fox jumps over the lazy dog 12345.'

正则表达式中的特殊字符与转义

正则表达式中的元字符是具有特殊含义的字符,用于构建匹配文本的模式。以下是对各种元字符和如何转义它们的详细介绍。

1. 元字符

  • 锚点^$

    • 功能:匹配字符串的开头和结尾。

    • 示例

      javascript 复制代码
      let str = 'Hello World';
      let re = /^Hello/;
      console.log(re.test(str)); // true
  • 交替|

    • 功能:表示"或"的关系。

    • 示例

      javascript 复制代码
      let str = 'apple or orange';
      let re = /apple|orange/;
      console.log(re.test(str)); // true
  • 量词+, ?, {}

  • 预定义字符类\d, \w, \s

    • 功能:匹配数字、单词字符和空白字符。

    • 示例

      javascript 复制代码
      let str = '2022';
      let re = /\d{4}/;
      console.log(re.test(str)); // true

2. 点号(.

  • 功能 :匹配除换行符 \n 外的任何单个字符。

  • 示例

    javascript 复制代码
    const regex = /a.b/;
    console.log(regex.test('acb')); // true
    console.log(regex.test('aXb')); // true
    console.log(regex.test('a\nb')); // false
  • 使用 /s 标志匹配换行符

    javascript 复制代码
    const regex = /a.b/s;
    console.log(regex.test('a\nb')); // true

3. 结合点号与其他元素

  • 示例

    javascript 复制代码
    const regex = /.at/;
    console.log(regex.test('cat')); // true
    console.log(regex.test('bat')); // true
    console.log(regex.test('hat')); // true

4. 转义特殊字符

  • 功能:将特殊字符作为普通字符匹配。
  • 方法 :在特殊字符前加反斜杠 \

常见特殊字符

  • .^$*+?|{}[]()\

示例

  1. 匹配字面符号 ^

    javascript 复制代码
    let str = 'This ^ symbol is called Caret';
    let re = /[\^]/g;
    let results = str.match(re);
    console.log(results); // 输出为:['^']
  2. 匹配反斜杠 /

    javascript 复制代码
    let str = 'Use / to escape characters';
    let re = /[\/]/g;
    let results = str.match(re);
    console.log(results); // 输出为:['/']

综合示例

以下是一个更复杂的示例,结合了多种元字符和转义:

javascript 复制代码
let text = "The price is $5.99 for item #1234.";
let re = /\$\d+\.\d{2}/;
let results = text.match(re);
console.log(results); // 输出为:['$5.99']
  • 解释
    • \$:匹配美元符号 $
    • \d+:匹配一个或多个数字。
    • \.:匹配点号 .
    • \d{2}:匹配两个数字。

正则表达式中的分组

在正则表达式中,分组是通过将模式的一部分括在括号中来实现的。分组可以用来提取匹配的子字符串、应用量词或进行交替匹配。以下是关于捕获组、命名捕获组、非捕获组、后向引用和选择符号的详细说明和示例。

1. 捕获组

捕获组用于提取匹配的子字符串。你可以在正则表达式中使用括号 () 来创建捕获组。

示例

  • 匹配路径并捕获ID部分
javascript 复制代码
const path = 'posts/123';
const pattern = /\w+\/(\d+)/;

const match = path.match(pattern);
console.log(match);
// 输出为:['posts/123', '123', index: 0, input: 'posts/123', groups: undefined]

2. 使用多个捕获组

示例

  • 捕获资源和ID
javascript 复制代码
const path = 'posts/123';
const pattern = /(\w+)\/(\d+)/;

const match = path.match(pattern);
console.log(match);
// 输出为:['posts/123', 'posts', '123', index: 0, input: 'posts/123', groups: undefined]

3. 命名捕获组

命名捕获组使引用更方便,语法为 (?<name>pattern)

示例

  • 捕获资源和ID
javascript 复制代码
const path = 'posts/123';
const pattern = /(?<resource>\w+)\/(?<id>\d+)/;

const match = path.match(pattern);
console.log(match.groups);
// 输出为:{ resource: 'posts', id: '123' }
  • 捕获完整日期
javascript 复制代码
const path = 'posts/2024/02/22';
const pattern = /(?<resource>\w+)\/(?<year>\d{4})\/(?<month>\d{2})\/(?<day>\d{2})/;

const match = path.match(pattern);
console.log(match.groups);
// 输出为:{ resource: 'posts', year: '2024', month: '02', day: '22' }

4. 非捕获组

非捕获组用于组合模式的一部分,但不捕获匹配的子字符串,语法为 (?:pattern)

示例

  • 捕获组 vs 非捕获组
javascript 复制代码
// 捕获组
const regexWithCapture = /(\d{2})\/(\d{2})\/(\d{4})/;
const matchWithCapture = regexWithCapture.exec('02/26/2024');
console.log(matchWithCapture);
// 输出为:["02/26/2024", "02", "26", "2024"]

// 非捕获组
const regexWithoutCapture = /(?:\d{2})\/(?:\d{2})\/(?:\d{4})/;
const matchWithoutCapture = regexWithoutCapture.exec('02/26/2024');
console.log(matchWithoutCapture);
// 输出为:["02/26/2024"]

5. 后向引用

后向引用允许你在正则表达式中引用先前捕获的组,语法为 \N,其中 N 是捕获组的编号。

示例

  • 移除重复的单词
javascript 复制代码
const s = 'Lion Lion is the King';
const pattern = /(\w+)\s+\1/;
const result = s.replace(pattern, '$1');
console.log(result);
// 输出为:'Lion is the King'

6. 正则表达式选择符号

选择符号 | 用于匹配多个模式中的一个。

示例

  • 匹配有效时间字符串 hh:mm
javascript 复制代码
const timeString = '07:23 33:71 21:17 25:81';
const pattern = /([01]\d|2[0-3]):[0-5]\d/g;
const matches = timeString.match(pattern);
console.log(matches);
// 输出为:['07:23', '21:17']

综合示例

以下是一个结合捕获组、命名捕获组、非捕获组和选择符号的综合示例:

javascript 复制代码
const text = 'Order #12345 shipped on 2024/02/22';
const pattern = /Order #(?<orderId>\d+) shipped on (?<year>\d{4})\/(?<month>\d{2})\/(?<day>\d{2})/;

const match = text.match(pattern);
console.log(match.groups);
// 输出为:{ orderId: '12345', year: '2024', month: '02', day: '22' }

正则表达式中的前瞻断言和后顾断言

前瞻断言和后顾断言是正则表达式中的高级特性,用于基于上下文条件匹配模式。

1. 前瞻断言

前瞻断言允许匹配某个模式 (X),仅当其后紧跟着特定模式 (Y) 时才匹配。语法是 X(?=Y)

示例

  • 匹配后跟"miles"的数字
javascript 复制代码
const dist = "He ran 5 miles, but not 10 kilometers.";
const regex = /\d+(?=\s*miles)/g;
console.log(dist.match(regex)); // 输出为:["5"]
  • 多重前瞻断言X(?=Y)(?=Z) 允许施加多个条件。
javascript 复制代码
const regex = /(?=.*foo)(?=.*bar)/;
console.log(regex.test("foobar")); // true
console.log(regex.test("barfoo")); // true
console.log(regex.test("foo"));    // false
console.log(regex.test("bar"));    // false

2. 否定前瞻断言

否定前瞻断言匹配模式 (X),仅当其后不跟着特定模式 (Y) 时匹配。语法是 X(?!Y)

示例

  • 匹配不跟"miles"的数字
javascript 复制代码
const text = "He ran 5 miles, but not 10 kilometers.";
const regex = /\d+(?!\s*miles)/g;
console.log(text.match(regex)); // 输出为:["10"]

3. 后顾断言

后顾断言根据其前面的内容匹配模式。语法是 (?<=Y)X

示例

  • 匹配在 "$" 符号前的数字
javascript 复制代码
const priceString = "The price is $100, but €200.";
const regex = /(?<=\$)\d+/g;
console.log(priceString.match(regex)); // 输出为:["100"]

4. 否定后顾断言

否定后顾断言匹配模式 (X),仅当其前面不跟特定模式 (Y) 时匹配。语法是 (?<!Y)X

示例

  • 匹配不是以 "$" 开头的数字
javascript 复制代码
const priceString = "The price is $50, but not €100.";
const regex = /(?<!\$)\b\d+\b/g;
console.log(priceString.match(regex)); // 输出为: ["100"]

综合示例

以下是结合前瞻断言、否定前瞻断言、后顾断言和否定后顾断言的示例:

javascript 复制代码
const text = "Contact: +1-202-555-0173, Fax: 202-555-0199";
const regex = /(?<=\+1-)\d{3}(?=-\d{4})/g;
console.log(text.match(regex)); // 输出为:["202"]

const negateExample = "Discount: $50, Promo: €30, Coupon: £20";
const negateRegex = /(?<!€|£)\d+/g;
console.log(negateExample.match(negateRegex)); // 输出为:["50"]

详细解释

  1. 前瞻断言 (?=Y)

    • 仅当 X 后面紧跟 Y 时,匹配 X。
    • 示例\d+(?=\s*miles) 匹配 "5" (前后有 "miles")。
  2. 否定前瞻断言 (?!Y)

    • 仅当 X 后面不跟 Y 时,匹配 X。
    • 示例\d+(?!\s*miles) 匹配 "10" (前后没有 "miles")。
  3. 后顾断言 (?<=Y)

    • 仅当 X 前面有 Y 时,匹配 X。
    • 示例(?<=\$)\d+ 匹配 "100" (前面有 "$")。
  4. 否定后顾断言 (?<!Y)

    • 仅当 X 前面不跟 Y 时,匹配 X。
    • 示例(?<!\$)\b\d+\b 匹配 "100" (前面没有 "$")。

10个正则表达式的实际应用示例

  1. 匹配中国手机号

    正则表达式^(13[0-9]|14[5-9]|15[0-3,5-9]|16[6]|17[0-8]|18[0-9]|19[8,9])\d{8}$

    示例

    javascript 复制代码
    let phone = '19888881110';
    let regex = /^(13[0-9]|14[5-9]|15[0-3,5-9]|16[6]|17[0-8]|18[0-9]|19[8,9])\d{8}$/;
    console.log(regex.test(phone)); // 输出为:true
  2. 匹配身份证号码

    正则表达式/^\d{15}|\d{18}$/

    示例

    javascript 复制代码
    let idCard = '11010519491231002X';
    let regex = /^\d{15}|\d{18}$/;
    console.log(regex.test(idCard)); // 输出为:true
  3. 匹配邮政编码

    正则表达式/^[1-9]\d{5}$/

    示例

    javascript 复制代码
    let postalCode = '100000';
    let regex = /^[1-9]\d{5}$/;
    console.log(regex.test(postalCode)); // 输出为:true
  4. 匹配中文字符

    正则表达式/[\u4e00-\u9fa5]/

    示例

    javascript 复制代码
    let text = '你好,世界!';
    let regex = /[\u4e00-\u9fa5]/;
    console.log(regex.test(text)); // 输出为:true
  5. 匹配车牌号

    正则表达式/^[\u4e00-\u9fa5][A-Z][A-Z0-9]{5}$/

    示例

    javascript 复制代码
    let licensePlate = '京A12345';
    let regex = /^[\u4e00-\u9fa5][A-Z][A-Z0-9]{5}$/;
    console.log(regex.test(licensePlate)); // 输出为:true
  6. 匹配固定电话号码

    正则表达式/^(0\d{2,3})-?(\d{7,8})$/

    示例

    javascript 复制代码
    let phone = '010-12345678';
    let regex = /^(0\d{2,3})-?(\d{7,8})$/;
    console.log(regex.test(phone)); // 输出为:true
  7. 匹配QQ号码

    正则表达式/^[1-9][0-9]{4,}$/

    示例

    javascript 复制代码
    let qq = '12345678';
    let regex = /^[1-9][0-9]{4,}$/;
    console.log(regex.test(qq)); // 输出为:true
  8. 匹配邮箱地址

    正则表达式:`/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$/

    示例

    javascript 复制代码
    let email = 'example@qq.com';
    let regex = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/;
    console.log(regex.test(email)); // 输出为:true
  9. 匹配日期格式 (yyyy-mm-dd)

    正则表达式/^\d{4}-\d{2}-\d{2}$/

    示例

    javascript 复制代码
    let date = '2024-05-10';
    let regex = /^\d{4}-\d{2}-\d{2}$/;
    console.log(regex.test(date)); // 输出为:true
  10. 匹配IP地址

    正则表达式/^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/

    示例

    javascript 复制代码
    let ip = '192.168.1.1';
    let regex = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$/;
    console.log(regex.test(ip)); // 输出为:true

使用正则表达式的技巧和最佳实践

以下是一些使用正则表达式的技巧和最佳实践,帮助你更有效地编写和使用正则表达式。

1. 理解正则表达式语法

要点

  • 熟悉正则表达式的基本语法和元字符,如 ^, $, \d, \w, . 等。

示例

javascript 复制代码
const regex = /^\d{4}-\d{2}-\d{2}$/; // 匹配日期格式 yyyy-mm-dd

2. 测试正则表达式

要点

  • 使用多种输入测试正则表达式,确保其在各种情况下都能正常工作。

示例

javascript 复制代码
const regex = /^\d{4}-\d{2}-\d{2}$/;
console.log(regex.test('2024-05-11')); // true
console.log(regex.test('05-11-2024')); // false

3. 优化性能

要点

  • 简化正则表达式模式,避免不必要的复杂性。

示例

javascript 复制代码
// 原始正则表达式
const regex1 = /(a|b|c|d)/;

// 优化后的正则表达式
const regex2 = /[abcd]/;

4. 使用内置方法

要点

  • 使用 JavaScript 提供的内置方法进行常见字符串操作,如 match(), replace(), split() 等。

示例

javascript 复制代码
let str = 'The quick brown fox';
let words = str.split(' ');
console.log(words); // ["The", "quick", "brown", "fox"]

5. 为你的正则表达式添加注释

要点

  • 使用 (?#comment) 语法添加注释,解释复杂模式的含义。

示例

javascript 复制代码
const regex = /(\d{3})-(\d{3})-(\d{4})\s(?# Match phone number format +86-XXXXXXX)/;

6. 分解复杂模式

要点

  • 将复杂的正则表达式分解为更小的部分,使用变量存储各个组件,然后组合它们。

示例

javascript 复制代码
const areaCode = '\\d{3}';
const phoneNumber = '\\d{3}-\\d{4}';
const regex = new RegExp(`^(${areaCode})-(${phoneNumber})$`);

7. 利用在线资源并坚持练习

要点

  • 使用在线工具如 Regex101 和 RegExr 进行正则表达式测试和学习。
  • 定期练习和参考 MDN Web Docs 等文档。

示例

综合示例

以下是一个将多个技巧结合起来的综合示例:

javascript 复制代码
// 目标:验证中国大陆手机号码并提取区号和号码

// 分解正则表达式
const countryCode = '\\+86'; // 中国大陆区号
const separator = '-'; // 分隔符
const phoneNumber = '\\d{10}'; // 10位手机号码

// 组合成完整正则表达式
const regex = new RegExp(`^(${countryCode})${separator}(${phoneNumber})$`);

// 测试字符串
const phone = '+86-13800138000';

// 测试正则表达式
console.log(regex.test(phone)); // true

// 提取匹配组
const match = phone.match(regex);
console.log(match); // ["+86-13800138000", "+86", "13800138000"]

// 输出匹配结果
if (match) {
  console.log(`区号: ${match[1]}`); // 区号: +86
  console.log(`手机号码: ${match[2]}`); // 手机号码: 13800138000
}

正则语法大全

正则表达式元字符与语法

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,"n"匹配字符"n"。"\n"匹配一个换行符。串行"\"匹配"\"而"("则匹配"("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^也匹配"\n"或"\r"之后的位置。
$ 匹配输入字符串的结束位置。如果设置了 RegExp 对象的 Multiline 属性,$也匹配"\n"或"\r"之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo*能匹配"z"以及"zoo"。*等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,"zo+"能匹配"zo"以及"zoo",但不能匹配"z"。+等价于{1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?"可以匹配"does"或"does"中的"do"。?等价于{0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个 o。
{n,} n 是一个非负整数。至少匹配 n 次。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有 o。"o{1,}"等价于"o+"。"o{0,}"则等价于"o*"。
{n,m} m 和 n 均为非负整数,其中 n<=m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}"将匹配"fooooood"中的前三个 o。"o{0,1}"等价于"o?"。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串"oooo","o+?"将匹配单个"o",而"o+"将匹配所有"o"。
. 要匹配除"\n"之外的任何单个字符,请使用 .。要匹配包括"\n"在内的任何字符,请使用像 (.竖线\n) 的模式。
(pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在 VBScript 中使用 SubMatches 集合,在 JScript 中则使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ... 0... </math>0...9 属性。要匹配圆括号字符,请使用"("或")"。
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符"( 竖线 )"来组合一个模式的各个部分是很有用。例如"industr(?:y 竖线 ies)"就是一个比"industry|industries"更简略的表达式。
(?=pattern) 正向肯定预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 正向否定预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern) 反向肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?<!pattern) 反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。
x 竖线 y 匹配 x 或 y。例如,"z 竖线 food"能匹配"z"或"food"。"(z 竖线 f)ood"则匹配"zood"或"food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如,"[abc]"可以匹配"plain"中的"a"。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如,"[^abc]"可以匹配"plain"中的"p"。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,"[a-z]"可以匹配"a"到"z"范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,"[^a-z]"可以匹配任何不在"a"到"z"范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,"er\b"可以匹配"never"中的"er",但不能匹配"verb"中的"er"。
\B 匹配非单词边界。"er\B"能匹配"verb"中的"er",但不能匹配"never"中的"er"。
\cx 匹配由 x 指明的控制字符。例如,\cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的"c"字符。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c 和\cL。
\n 匹配一个换行符。等价于\x0a 和\cJ。
\r 匹配一个回车符。等价于\x0d 和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09 和\cI。
\v 匹配一个垂直制表符。等价于\x0b 和\cK。
\w 匹配包括下划线的任何单词字符。等价于"[A-Za-z0-9_]"。
\W 匹配任何非单词字符。等价于"[^A-Za-z0-9_]"。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定 的两个数字长。例如,"\x41"匹配"A"。"\x041"则等价于"\x04&1"。正则表达式中可以使用 ASCII 编码。
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,"(.)\1"匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果\n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字(0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果\nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果\nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字(0-7),则\nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字(0-3),且 m 和 l 均为八进制数字(0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如,\u00A9 匹配版权符号(©)。

常用正则表达式

用途 正则表达式
用户名 /^[a-z0-9_-]{3,16}$/
密码 /^[a-z0-9_-]{6,18}$/
十六进制值 /^#?([a-f0-9]{6} 竖线 [a-f0-9]{3})$/
电子邮箱 /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/ /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/
URL /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
IP 地址 /((2[0-4]\d 竖线 25[0-5] 竖线[01]?\d\d?)\.){3}(2[0-4]\d 竖线 25[0-5] 竖线 [01]?\d\d?)$/ /^(?:(?:25[0-5] 竖线 2[0-4][0-9] 竖线 [01]?[0-9][0-9]?)\.){3}(?:25[0-5] 竖线 2[0-4][0-9] 竖线 [01]?[0-9][0-9]?)$/
HTML 标签 /^<([a-z]+)([^<]+)_(?:>(._)<\/\1> 竖线 \s+\/>)$/
删除代码注释 (?<!http: 竖线 \S)//.\*$
Unicode 编码中的汉字范围 /^[\u2E80-\u9FFF]+$/
相关推荐
向前看-19 分钟前
验证码机制
前端·后端
燃先生._.1 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
超爱吃士力架2 小时前
邀请逻辑
java·linux·后端
高山我梦口香糖2 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235242 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar3 小时前
纯前端实现更新检测
开发语言·前端·javascript
AskHarries4 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css