使用正则表达式验证数据正确吗?

7

我找到了一些文章和帖子,建议不要使用正则表达式来验证用户数据。我不确定所有的事情,但通常在验证电子邮件地址时会发现这种情况。

所以我想弄清楚使用正则表达式来验证用户输入是否好?如果它是好的,那么用它验证电子邮件地址有什么问题吗?

编辑:

那么我们可以说,对于基本的主要数据类型验证,我们可以使用正则表达式,这是好的,而对于完整的验证,我们需要将其与另一个解析器结合使用。

至于电子邮件验证的第二部分,在一般情况下我们可以使用它,但根据标准来说,它是不合适的。是吗?

现在我对选择正确答案感到困惑。

8个回答

4

好处在于您可以轻松地使用正则表达式来表示和测试复杂的模式。

坏处在于正则表达式可能很复杂,而且有很多错误的可能性。


编辑    好吧,这是一些真正的建议:首先,请确保期望的有效值是否可以用正则表达式表达。也就是说,当有效值的语言是正则语言时。否则,您就不能仅使用正则表达式(或至少不仅使用正则表达式)!

现在我们知道了可以使用正则表达式验证什么,我们应该讨论什么可以使用正则表达式进行验证。以电子邮件地址为例(像其他许多人一样),我们应该知道有效的电子邮件地址可能看起来像什么(请参见RFC 5322):

addr-spec       =   local-part "@" domain
local-part      =   dot-atom / quoted-string / obs-local-part
domain          =   dot-atom / domain-literal / obs-domain
domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
dtext           =   %d33-90 /          ; Printable US-ASCII
                    %d94-126 /         ;  characters not including
                    obs-dtext          ;  "[", "]", or "\"
在此,我们可以看到本地部分可以由引用字符串组成,该字符串可以包含任何可打印的US-ASCII字符(不包括\",但包括@)。因此,如果我们想要允许符合RFC 5322的地址,仅测试电子邮件地址是否包含一个@是不足够的。
另一方面,如果我们想要允许根据RFC 5322的任何有效电子邮件地址,则还将允许可能不存在或在大多数情况下毫无意义的地址(例如""@localhost)。

那么,对于数据验证的第一步来说,使用正则表达式是很好的选择,然后再使用另一个解析器进行完整的验证。 - KoolKabin
1
@KoolKabin:使用正则表达式只能满足语法测试,而不能满足语义测试。语法有效意味着它符合标准。语义有效意味着它在您想要使用的领域/区域中是有意义的。 - Gumbo

3
您的问题似乎有两个部分:(1)使用正则表达式进行数据验证是否不好,(2)使用它们验证电子邮件地址是否不好?
对于(1),这取决于具体情况。在许多情况下,正则表达式将足以验证用户输入;例如,验证用户名只包含字母数字字符。当输入可能会传递给诸如数据库查询或eval()语句之类的内容时,一组正则表达式可能不足够。在这些情况下,可能存在像递归之类无法处理的语言结构,并且通常需要了解目标语言的内容才能进行验证(和净化)。
在大多数情况下,您需要转义输入,以使其成为目标语言中的无害字符串。
如果您正在验证代码的正确性,则需要一个完整的解析器。解析器可以使用正则表达式,但通常解析器使用其他工具来完成重要的工作。

我同意将我的问题分成两个部分。因此,首先使用正则表达式进行数据验证的第一步,然后再使用另一个解析器进行完整验证是很好的选择。那么第二部分的电子邮件怎么办? - KoolKabin
我对验证电子邮件地址的情况了解不够,无法确定哪种方法更好。我的感觉是这个问题足够复杂,你可能需要使用现有的库来解决它,但我也看到一些正则表达式尝试验证电子邮件地址,这些可能足够了。如果您需要高水平的正确性,我建议熟悉相关的RFC。这可能会更加困难,因为并非所有电子邮件提供商都要求严格有效的电子邮件地址。这只是一些想法 - 其他人会更清楚。 - Eric Walker

2
正则表达式可能有三个缺点:
  1. 它们可以变得非常复杂,最终难以维护。很容易出错。
  2. 某些类型的文本根本无法使用正则表达式解析(例如HTML)。基本上,任何具有嵌套模式的内容都不能使用正则表达式解析。例如,您无法使用正则表达式解析编程语言。
  3. 根据您正在处理的文本类型,如果您只是编写自己的代码来解析它,可能会更容易和清晰。
但是,如果这些问题对您正在处理的内容不构成问题,那么使用正则表达式就没有问题。我认为验证电子邮件地址是正则表达式的一个好用途。

2
正则表达式是一种像其他工具一样的工具,尽管它是非常强大的。
它们非常强大,以至于使用它们的人往往会遭受到“当你手里只有锤子时,所有东西都看起来像钉子”的问题。这导致它们被用于其他方法更冗长但更有效和更易维护的情况。
在电子邮件地址的特定情况下,主要问题在于有大量的正则表达式声称可以验证电子邮件地址语法,但存在导致错误负面影响的问题。
它们的主要问题包括:
- 在地址的前半部分中禁止使用加号字符(尽管它们相对常见) - 将顶级域名限制为三个字符(这将阻止.museum顶级域名) - 将顶级域名限制为两个字符的国家代码TLD或特定TLD列表(因此每当新TLD出现时就必须更新它——猜猜发生了什么?)
电子邮件地址非常复杂,因此正则表达式实际上不应该做任何比以下更多的事情:
1. 不包括“@”的内容 2. 一个“@” 3. 不包括“@”的内容 4. 一个“.” 5. 不包括“@”的内容

电子邮件地址的“local-part”实际上可以包含@符号,只是不太常见。 - MikeD

1

对于电子邮件地址,使用正则表达式是很好的选择。它在大多数情况下都能起作用。

总的来说:您应该使用正则表达式验证任何可以表示为正则语言的内容。


这取决于您使用的正则表达式。我见过太多的假阴性结果,不鼓励人们在电子邮件地址检查中使用正则表达式(至少不带有大量的限制条件)。 - Quentin
“它在大多数情况下都能正常工作。”- 我认为这使得使用正则表达式变得糟糕。一个会出现误判或漏判的正则表达式是有缺陷的。 - Stephen C

1
如果您要验证的数据模式可以完全正确地使用正则表达式表达,那么您可以放心地使用它们。然而,并非所有文本模式都可以使用正则表达式来表示(例如上下文无关文法)。在这种情况下,您可能需要编写解析器或自定义方法来验证数据。

0

这些问题可能是因为通常使用的正则表达式未能涵盖所有可能的(有效)输入,或者限制了用户输入的太多。

我认为没有其他方法来验证某个用户输入是否符合某个模式(我的意思是,这就是正则表达式的用途),因此它们对于用户输入验证至关重要。但是你确实需要花一些时间来设计一个表达式,以确保它在极端情况下也能正常工作。

以信用卡号为例,您必须考虑用户可能输入的方式:

1234-5678
// or
1234 5678
// or
1234 - 5678

现在你有两种可能性:

  1. 你将输入限制在第一种情况下,这将导致更简单的表达式,但会最大程度地限制(甚至可能使用户感到烦恼)。
  2. 你可以创建一个接受任何这些可能性的表达式,使表达式更复杂(因此更难维护),但更加用户友好。

这是一个权衡。


4
你可以接受任何输入,但必须去掉任何非数字字符,并验证该值,如果需要,重新格式化它。 - Gumbo
关注点可能在于使用的正则表达式通常不能涵盖所有可能的(有效)输入,或者限制用户输入的内容太多。这可以适用于任何验证方法。 - Justin Johnson
@Gumbo:好观点 :) 这可能在这里起作用,但我更多地考虑它作为一个普遍的例子。 - Felix Kling

0

如果数据是正则语言,那么正则表达式并不适用于验证大多数数据。

但是,有时候它们会变得难以维护,程序员会引入错误。

缓解这种情况的最简单方法是使用测试/TDD。这些测试应该调用一个使用正则表达式来验证电子邮件地址的方法(我目前使用的正则表达式是/^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$/i,效果还不错)。这样,当您得到假阳性或假阴性时,可以为该情况添加另一个测试,调整您的正则表达式,并确保您没有破坏其他条件。

如果TDD似乎有点过头了,像Expresso这样的工具可以让您保存带有测试数据的正则表达式,并有助于跟踪应该通过/失败的值,并帮助创建和理解您的正则表达式。

警告:

在构建正则表达式时要小心。可能会引入ReDos漏洞。

请参见:http://msdn.microsoft.com/en-us/magazine/ff646973.aspx

简而言之,一个构造不良的正则表达式,在给定正确的输入情况下可能需要数小时才能有效地执行,从而破坏您服务器的性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接