返回

正则之路:一波未平一波又起

前端

正则表达式可谓是一把双刃剑,用得好,可以轻松完成字符串处理和数据验证任务;用得不好,则可能引发难以预料的问题。前些日子,我在做线上验品抽检需求时,就遇到了一个使用正则表达式进行ID验证的经典案例,也让我深刻体会到了正则表达式的不易掌控。

需求很简单,需要在开发发起检测任务页面添加一个字段校验功能,具体要求是:“用户可以填入多组ID,每组ID可以由商品ID和SKU ID共同构成,也可以只由其中一种ID构成,两种ID之间通过冒号分隔;每组ID之间又需要通过英文逗号分隔”。乍一看,这个需求似乎并不复杂,但实际上却隐藏着不小的挑战。

我按照需求给出的规则,编写了正则表达式:

/^([0-9]+|[0-9]+:[0-9]+)(,[0-9]+|[0-9]+:[0-9]+)*$/

这个正则表达式表示:

  • ^:匹配字符串的开头。
  • ([0-9]+|[0-9]+:[0-9]+):匹配一个组ID,可以是纯数字,也可以是商品ID和SKU ID组合,中间用冒号分隔。
  • (,[0-9]+|[0-9]+:[0-9]+)*:匹配零个或多个组ID,每个组ID之间用逗号分隔。
  • $:匹配字符串的结尾。

然而,当开发人员使用这个正则表达式进行验证时,却发现了一些意料之外的问题。首先,当用户输入一个纯数字的ID时,正则表达式可以正确匹配,但当用户输入一个包含冒号的ID时,正则表达式却无法匹配,这显然是不符合需求的。其次,当用户输入一个包含多个组ID的字符串时,正则表达式可以正确匹配,但如果用户不小心在字符串的末尾多输入了一个逗号,正则表达式也会匹配通过,这也会导致数据校验的失败。

经过一番排查,我终于找到了问题所在。原来,正则表达式中存在一个贪婪匹配的问题。在正则表达式中,量词(如*、+、?等)默认是贪婪的,这意味着它们会尽可能多地匹配字符。在上面的正则表达式中,量词*用于匹配零个或多个组ID,这意味着它会尽可能多地匹配组ID,直到遇到一个不匹配的字符为止。这就是为什么当用户输入一个包含多个组ID的字符串时,正则表达式可以正确匹配,但如果用户不小心在字符串的末尾多输入了一个逗号,正则表达式也会匹配通过。

为了解决这个问题,我将量词改为非贪婪匹配,即?。非贪婪匹配意味着量词会尽可能少地匹配字符,直到遇到一个不匹配的字符为止。这样,当用户输入一个包含多个组ID的字符串时,正则表达式只会匹配到最后一个组ID,而不会匹配到多余的逗号。

/^([0-9]+|[0-9]+:[0-9]+)(,[0-9]+|[0-9]+:[0-9]+)*)?$/

修改后的正则表达式可以完美地满足需求,不仅可以正确匹配纯数字的ID和包含冒号的ID,还可以正确处理包含多个组ID的字符串,即使用户不小心在字符串的末尾多输入了一个逗号,也不会导致数据校验失败。

这次经历让我深刻体会到了正则表达式的复杂性和易错性。虽然正则表达式是一种非常强大的工具,但如果使用不当,也可能成为一场灾难的根源。因此,在使用正则表达式时,一定要仔细考虑正则表达式的匹配规则,并充分测试正则表达式,以确保它能够满足需求。