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

Jay*_*ran 98 regex

这是我在JavaScript中创建的正则表达式:

var reg_num = /^(7|8|9)\d{9}$/
Run Code Online (Sandbox Code Playgroud)

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

var reg_num = /^[7|8|9][\d]{9}$/
Run Code Online (Sandbox Code Playgroud)

规则是验证电话号码:

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

Boh*_*ian 112

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

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

  • `(7 | 8 | 9)`和`[789]`不等同,因为第一个是捕获,后者不是.另一方面,`(?:7 | 8 | 9)`相当于(我想你当然知道......). (27认同)

Uni*_*ron 54

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

/^(7|8|9)\d{9}$/
Run Code Online (Sandbox Code Playgroud)

这是做什么的:

  • ^$表示锚定匹配,它断言在这些锚定件之间的子模式是整个匹配.如果子模式它的全部,而不仅仅是一个部分匹配字符串将只匹配.
  • ()表示捕获组.
  • 7|8|9表示匹配的任一7,89.它通过交替执行此操作,这是管道操作员|所做的 - 在交替之间交替.这在交替之间回溯:如果第一次交替不匹配,则在交替的匹配期间引擎必须在指针位置移动之前返回,以继续匹配下一次交替; 而字符类可以顺序前进.在禁用优化的正则表达式引擎上查看此匹配:
Pattern: (r|f)at
Match string: carat
Run Code Online (Sandbox Code Playgroud)

交替

Pattern: [rf]at
Match string: carat
Run Code Online (Sandbox Code Playgroud)

类

  • \d{9}匹配九位数.\d是一个短的元字符,匹配任何数字.
/^[7|8|9][\d]{9}$/
Run Code Online (Sandbox Code Playgroud)

看看它的作用:

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

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

  • 只是出于兴趣,该截图来自哪个程序? (4认同)
  • @MrMysteryGuest我想从那时起你就得到了答案,但对于任何想知道的人来说,来自Unihedron的[另一个线程中的评论](/sf/ask/1549271531/ -alternation#comment49574685_26141949) 这来自 https://regex101.com 的调试器。我认为从那时起调试器已经发生了变化,因为我没有静态的步骤列表,但我可以逐步推进。 (3认同)

小智 12

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

str = str.replace(/^(7|8|9)/ig,''); 
Run Code Online (Sandbox Code Playgroud)

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

如果你匹配这个

str = str.replace(/^[7|8|9]/ig,''); 
Run Code Online (Sandbox Code Playgroud)

你将替换7或者8或者9删除垂直条!由空字符串.

我刚刚发现了这个问题.

  • 欢迎来到SO!替换或匹配,这是完全错误的.很多人犯了这个错误,他们通常会侥幸逃脱 - 多年来,有时候 - 因为他们的输入字符串永远不会包含管道(`|`). (6认同)