正则表达式中方括号和括号之间有什么区别?

时间:2012-03-21 09:21:00

标签: regex

这是我在JavaScript中使用的正则表达式:

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

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

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

规则是验证电话号码:

  • 它应该只有十个数字。
  • 第一个数字应该是7,8或9中的任何一个。

3 个答案:

答案 0 :(得分:103)

这些正则表达式是等效的(出于匹配目的):

  • /^(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)的操作,但不会转换为字符类。

答案 1 :(得分:53)

除了他犯的错误之外,你的团队的建议几乎正确。一旦找到原因,就永远不会忘记它。看看这个错误。

/^(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}匹配九位数。 \d是一个简短的元字符,匹配任何数字。
/^[7|8|9][\d]{9}$/

看看它的作用:

  • ^$也表示锚定匹配。
  • [7|8|9]字符类。列表7|8|9中的所有字符都可以匹配,因此|被错误地添加。这种匹配没有回溯。
  • [\d]是一个居住在元字符\d中的字符类。顺便说一下,使用字符类和单个元字符的组合是一个坏主意,因为抽象层可能会降低匹配速度,但这只是一个实现细节,仅适用于一些正则表达式实现。 JavaScript不是一个,但它确实使子模式稍长。
  • {9}表示前一个单一构造总共重复九次。

最佳正则表达式为/^[789]\d{9}$/,因为/^(7|8|9)\d{9}$/会不必要地捕获,这会导致大多数正则表达式实现性能下降(恰好为1,考虑到问题使用关键字{{1}在代码中,这可能是JavaScript)。使用在PCRE上运行的进行preg匹配将优化缺少回溯,但我们也不在PHP中,因此使用类var而不是替换[]因为匹配没有回溯,所以提供了性能加值,因此比使用之前的正则表达式更快地匹配和失败。

答案 2 :(得分:11)

如果您通过某些内容替换它们,前两个示例的行为会有很大不同。如果你匹配这个:

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

你会用空字符串替换7或8或9。

如果你匹配

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

您将替换789或垂直条!由空字符串。

我刚刚发现了这个问题。