JavaScript 中正则表达式(RegEx)实用指南

F2E 前端

图片由 NeONBRAND 提供 Unsplash

初次接触正则表达式,它们看起来就像是一堆杂乱无章的字符。虽然它们看起来很怪(拥有很奇怪的语法),但是它们相当的有用。

正确的理解正则表达式可以让你成为更有效的编程者。为了你能完全理解正则语句,首先你要学习它的基本概念,然后以此为基础使用。

言归正传,让我们开始吧 :)

什么是正则表达式?

正则表达式是描述字符串数据模式的一种方式。它们形成了自己的小语言,是众多编程语言的一部分,像 Javascript、Perl、Python、Php、和 Java。

正则表达式允许你检查字符串的模式,像电子邮件、密码等,来查看它们是否与正则表达式定义的模式匹配,并产生可操作消息。

创建一个正则表达式

在 JavaScript 中有两种方式可以创建正则表达式。可以使用 RegExp 构造器,或者使用斜线 ( / )把模式括起来。

正则表达式构造器

语法: new RegExp(pattern[, flags])

示例:

var regexConst = new RegExp('abc');

正则表达式字面量

语法:/pattern/flags

示例:

var regexLiteral = /abc/;
  • 这里的标志是可选的,文章后面会介绍到。

在一些情况下,你可能需要动态创建正则表达式,这样中情况下,正则表达式字面量就无法工作量,那么你就必须使用正则表达式构造器了。

无论选择哪种方法,结果都是一个 regex 对象。两个 regex 对象都有相同的方法和属性。

上面的例子中,斜杠是用来包装模式的,如果你想要在正则中使用斜杠,就需要使用 ( \) 转义  ( / )

正则表达式方法

测试正则表达式的方法主要有两种。

RegExp.prototype.test()

这个方法用来测试匹配是否找到。它会接受我们必须针对正则表达式进行测试的字符串,并根据是否找到匹配项来返回 true  或  false 

例如:

var regex = /hello/;

var str = 'hello world';

var result = regex.test(str);

console.log(result);

// returns true

RegExp.prototype.exec()

这个方法会返回包含所有匹配项的数组。它接受我们必须对正则表达式测试的字符串。

例如:

var regex = /hello/;

var str = 'hello world';

var result = regex.exec(str);

console.log(result);

// returns [ 'hello', index: 0, input: 'hello world', groups: undefined ]

// 'hello' -> 匹配模式。
// index: -> 正则表达式的起点。
// input: -> 实际传入的字符串。

本文会使用 test() 方法。

简单模式

这个最基础的模式,将文本与测试字符串匹配。例如:

var regex = /hello/;

console.log(regex.test('hello world'));

// true

特殊字符

目前为止,我们已经创建了一个简单的正则表达式了。现在,让我们充分使用正则表达式的能力,来解决更复杂的场景吧。

例如,我们不是匹配一个特定的邮箱,而是一系列邮箱。特殊字符的功能就派上用场了。为了全面掌握正则表达式,你必须记住这些特殊符号和字符。

标识符:

正则表达式有五个可选标识符及修改符。让我们探究一下最重要的两个:

  • g — 全局搜索,不会再第一次匹配返回
  • i — 不区分大小写搜索

你还可以在一个正则表达式中合并使用。注意它们的顺序不会对结果产生影响

让我们看下这些代码示例:

**正则表达式字面量 — **语法 /pattern/flags

var regexGlobal = /abc/g;

console.log(regexGlobal.test('abc abc'));

// 它会匹配所有出现的 'abc',所以不会再第一匹配到就返回

var regexInsensitive = /abc/i;

console.log(regexInsensitive.test('Abc'));

// 返回 true,因为在不区分大小写的搜索中,字符串的大小并不重要

**正则表达式构造器 — **语法 new RegExp('pattern', 'flags')

var regexGlobal = new RegExp('abc','g')

console.log(regexGlobal.test('abc abc'));

// 它会匹配所有出现的 'abc',所以不会再第一匹配到就返回

var regexInsensitive = new RegExp('abc','i')

console.log(regexInsensitive.test('Abc'));

// 返回 true,因为在不区分大小写的搜索中,字符串的大小并不重要

字符组:

字符集 [xyz] — 字符集是在一个位置匹配不同字符的方法,它可以匹配括号内字符中的任意一个。例如:

var regex = /[bt]ear/;

console.log(regex.test('tear'));
// 返回 true
console.log(regex.test('bear'));
// 返回 true
console.log(regex.test('fear'));
// 返回 false

注意 — 在字符集中所有特殊字符除 (^) (在字符集中有完全不同的意义) 外都会失去它原本的意义。

反向字符集 [^xyz] — 它匹配任何不在括号内的内容。例如:

var regex = /[^bt]ear/;

console.log(regex.test('tear'));
// 返回 false
console.log(regex.test('bear'));
// 返回 false
console.log(regex.test('fear'));
// 返回 true

范围 [a-z] — 假如我们想在一个位置上匹配所有的字母,我们可以在括号内写上所有的字母,但是这儿有更容易的方法就是 ranges。例如: [a-h] 会匹配所有 a 到 h 的字母。范围还可以是数字如 [0-9] 或者大写字母如 [A-Z]

var regex = /[a-z]ear/;

console.log(regex.test('fear'));
// 返回 true

console.log(regex.test('tear'));
// 返回 true

元字符— 元字符是字符具有特殊的意义。元字符有很多,这儿我只会介绍最重要的。

  • \d — 匹配任意数字 ( 等同于 [0-9] ).
  • \w — 匹配任何单词。这个字符可以是任意字母,数字和下划线。(等同于 [a-zA-Z0–9_] ) 也就是字母数字字符组。
  • \s— 匹配一个空白字符 (空格、制表符等)。
  • \t— 只匹配一个制表符。
  • \b— 在单词的开头或结尾找到一个匹配项。也称为词界
  • . — (句号)匹配除换行符之外的任意字符。
  • \D — 匹配任意非数字字符 (等同于[^0–9])。
  • \W — 匹配任意非单词字符(等同于 [^a-zA-Z0–9_] )。
  • \S — 匹配一个非空白字符。

数量词:—  数量词是正则表达式中具有特殊意义的符号。

  • + — 匹配前面的表达式1次或更多次。
var regex = /.+/;
console.log(regex.test('8'));
// true

console.log(regex.test('88899'));
// true

console.log(regex.test('8888845'));
// true
  • * **— 匹配前面的表达式0次或多次。
var regex = /go*d/;

console.log(regex.test('gd'));
// true

console.log(regex.test('god'));
// true

console.log(regex.test('good'));
// true

console.log(regex.test('goood'));
// true
  • — 匹配前面的表达式0或1次,即前面的模式是可选的。
var regex = /goo?d/;

console.log(regex.test('god'));
// true

console.log(regex.test('good'));
// true

console.log(regex.test('goood'));
// false
  • — 匹配字符串的开试位置,正则表达式应该位于测试字符串的开头。也就是 (^) 位于字符串的开头。
var regex = /^g/;

console.log(regex.test('good'));
// true

console.log(regex.test('bad'));
// false

console.log(regex.test('tag'));
// false
  • $ — 匹配字符串的结尾。正则表达式应该位于测试字符串的结尾。 ($) 符匹配字符串的结尾。
var regex = /.com$/;

console.log(regex.test('test@testmail.com'));
// true

console.log(regex.test('test@testmail'));
// false
  • {N} — 精准匹配其前面正则表达式的 N 次出现
var regex = /go{2}d/;

console.log(regex.test('good'));
// true

console.log(regex.test('god'));
// false
  • {N,} — 匹配其前正则表达式的至少 N 次出现
var regex = /go{2,}d/;

console.log(regex.test('good'));
// true

console.log(regex.test('goood'));
// true

console.log(regex.test('gooood'));
// true
  • {N,M} — 至少匹配 N 次,最多匹配前一个正则表达式的 M 次 (需 M > N).
var regex = /go{1,2}d/;

console.log(regex.test('god'));
// true

console.log(regex.test('good'));
// true

console.log(regex.test('goood'));
// false

间隔 X|Y — 匹配 X 或 Y。例如:

var regex = /(green|red) apple/;

console.log(regex.test('green apple'));
// true
console.log(regex.test('red apple'));
// true
console.log(regex.test('blue apple'));
// false

注意 —如果你想在表达式中使用任意字符串,比方说你想匹配字面量 + 或 .,你就必须使用反斜杠 ( \) 转义。

例如:

var regex = /a+b/;  // This won't workvar 

regex = /a.b/; // This will work

console.log(regex.test('a+b')); // true

高级篇

(x) — 匹配 x 并记住匹配。这些称为捕获组。这也用于在正则表达式中创建子表达式。例如:

var regex = /(foo)bar\1/;
console.log(regex.test('foobarfoo'));
// true

console.log(regex.test('foobar'));
// false

\1 记住并使用从括号内的第一个子表达式匹配的值。

(?:x) —匹配 x 但不记住这个匹配。这些称为非捕获组。这儿 \1 不会工作,它会匹配字面量 \1

var regex = /(?:foo)bar./;
console.log(regex.test('foobarfoo'));
// false

console.log(regex.test('foobar'));
// false

console.log(regex.test('foobar.'));
// true

x(?=y) —匹配 x 仅仅当 x 后面跟着 y。这种叫做先行断言。例如:

var regex = /Red(?=Apple)/;

console.log(regex.test('RedApple'));
// true

在上面的例子中,仅有当 Red后跟着 Apple 时会匹配。

Regex 实践:

让我们实践一下上面学到的概念。

  • 匹配任意十个数字:
var regex = /^\d{10}$/;

console.log(regex.test('9995484545'));
// true

让我们分解一下,看看都发生了什么。

  1. 如果我们强制匹配必须跨越整个字符串的话,我们可以添加量词 ^ 和 $。插入符 匹配字符串的开头,而 $ 符匹配结尾。所以在不是十位的时候不会被匹配。
  2. \d 匹配任意数字。
  3. {10} 匹配前面的表达式,在本例中 \d 正好匹配 10 次。所以若测试字符串少于或大于 10 个数字,结果都将为 false。
  • 匹配日期为接下来的格式 DD-MM-YYYY  或 DD-MM-YY
var regex = /^(\d{1,2}-){2}\d{2}(\d{2})?$/;
console.log(regex.test('01-01-1990'));
// true
console.log(regex.test('01-01-90'));
// true
console.log(regex.test('01-01-190'));
// false

让我们分解一下,看看都发生了什么。

  1. 同样,我们使用 和 $ 包裹整个正则表达式,所以就会匹配整个字符串。
  2. ( 第一个子表示式的开始。
  3. .{1,2} 匹配至少 1 个,至多 2 个数字。
  4. - 匹配文字连字符。
  5. ) 的哥子表达式的结束。
  6. {2} 正好匹配第一个子表达式 2 次。
  7. \d{2} 匹配正好 2 个数字。
  8. (\d{2})? 匹配 2 个数字。但它是可选的,所以年既可以为 2 位也可为 4 位数字。
  • *匹配除换行符之外的任意字符

这个表达式应该匹配任意格式为 abc.def.ghi.jkl 的字符串,其每个变量 a, b, c, d, e, f, g, h, i, j, k, l  都可以是出换行符之外的任意字符。

var regex = /^(.{3}\.){3}.{3}$/;

console.log(regex.test('123.456.abc.def'));
// true

console.log(regex.test('1243.446.abc.def'));
// false

console.log(regex.test('abc.def.ghi.jkl'));
// true

让我们分解一下,看看都发生了什么。

  1. 我们使用 ^$ 包裹整个正则表达式,所以就会匹配整个字符串。
  2. ( 第一个子表达式的开始。
  3. .{3} 匹配除换行符之外的任意字符 3 次。
  4. \. 匹配 . 句号。
  5. ) 第一个子表达式的结束。
  6. {3} 正好匹配第一个子表达式 3 次。
  7. .{3} 匹配除换行符之外的任意字符 正好3 次。

总结

正则表达式有时可能相当复杂,但是正确理解上述概念将帮助你轻松理解更复杂的正则表达式模式。你可在 这儿  学习正则表达式并在 这儿 进行实践练习。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://blog.bitsrc.io/a-beginners-guide...

译文地址:https://learnku.com/f2e/t/39272

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!