正则表达式中方括号和圆括号的区别是什么?

下面是我在 JavaScript 中创建的一个正则表达式:

var reg_num = /^(7|8|9)\d{9}$/

这是我的团队成员提出的另一个建议。

var reg_num = /^[7|8|9][\d]{9}$/

规则是验证一个电话号码:

  • 应该只有十个数字。
  • 第一个数字应该是7、8或9中的任意一个。
190775 次浏览

这些正则表达式是等价的(为了进行匹配) :

  • /^(7|8|9)\d{9}$/
  • /^[789]\d{9}$/
  • /^[7-9]\d{9}$/

解释:

  • (a|b|c)是正则表达式“ OR”,意思是“ a 或 b 或 c”,尽管存在方括号,这是 OR 所必需的,也是 捕捉的数字。为了严格等效,可以编写 (?:7|8|9)代码,使其成为 捕获组。

  • [abc]是一个“字符类”,意思是“ a、 b 或 c 中的任何字符”(字符类可以使用范围,例如 [a-d] = [abcd])

这些正则表达式之所以相似,是因为字符类是“或”的简写(但只适用于单个字符)。在一个交替,你也可以做一些像 (abc|def)这样的东西,不翻译成一个字符类。

前两个例子的作用非常不同,如果你用一些东西来代替它们:

str = str.replace(/^(7|8|9)/ig,'');

您可以用空字符串替换7、8或9。

如果你配上这个的话

str = str.replace(/^[7|8|9]/ig,'');

用空字符串替换 789或垂直条。

我也是吃了苦头才知道的。

您的团队的建议是 差不多是正确的,除了所犯的错误。一旦你找到原因,你永远不会忘记。看看这个错误。

/^(7|8|9)\d{9}$/

用途:

  • ^$表示锚定的匹配,它断言这些锚之间的子模式是整个匹配。只有当子模式匹配整个字符串时,字符串才会匹配,而不仅仅是匹配一个部分。
  • ()表示 捕捉组
  • 7|8|9表示与 789匹配。它使用 变化完成这项工作,这正是管道操作员 |所做的ーー在交替之间进行交替。这会在交替之间回溯: 如果第一个交替不匹配,引擎必须在交替匹配期间指针位置移动之前返回,以继续匹配下一个交替; 而字符类可以 顺序前进。在禁用优化的正则表达式引擎上查看这个匹配:
Pattern: (r|f)at
Match string: carat

alternations

Pattern: [rf]at
Match string: carat

class

  • \d{9}匹配9位数字。 \d是一个简写的元字符,可以匹配任何数字。
/^[7|8|9][\d]{9}$/

看看它做了什么:

  • ^$也表示锚定的匹配。
  • [7|8|9]性格类。可以匹配列表 7|8|9中的任何字符,因此不正确地添加了 |。这匹配没有回溯。
  • [\d]是驻留在元字符 \d中的字符类。顺便说一下,将一个字符类和一个元字符结合使用是一个坏主意,因为抽象层可能会减慢匹配速度,但是这只是一个实现细节,并且只适用于几个 regex 实现。JavaScript 不是其中之一,但它确实使子模式稍微变长了一些。
  • {9}表示前面的单个构造总共重复了9次。

最佳的正则表达式是 /^[789]\d{9}$/,因为 /^(7|8|9)\d{9}$/捕获了对大多数正则表达式实现造成性能下降的不必要的东西(考虑到问题在代码中使用关键字 var,这可能是 JavaScript)。使用运行在 PCRE 上的 进行预处理匹配将优化消除缺乏回溯,但是我们也不在 PHP 中,所以使用类 []而不是交替 |可以提高性能,因为匹配不会回溯,因此两者都比使用之前的正则表达式更快地匹配和失败。