40

尽管这似乎是一个微不足道的问题,但我很确定它不是:)

我需要验证来自世界各地的人的姓名和姓氏。想象一下我需要删除的大量姓名和姓氏的巨大列表,并尽可能删除我识别出的任何杂物。我怎样才能用正则表达式做到这一点?如果只是英文的,我认为这会削减它:

^[a-z -']+$

但是,我还需要支持这些情况:

  • 其他标点符号,因为它们可能在不同的国家/地区使用(不知道是哪个,但也许你会!)
  • 不同的 Unicode 字母集(重音字母、希腊语、日语、中文等)
  • 没有数字或符号或不必要的标点符号或符文等。
  • 标题、中间名首字母、后缀不是此数据的一部分
  • 名字已经被姓氏分开了。
  • 我们准备强制简化极其罕见的名字(存在一个名为'@'的人,但让这个角色无处不在是没有意义的。使用实用主义和良好的感觉。)
  • 请注意,许多国家/地区都有关于名称的法律,因此需要遵循一些标准

是否有一种标准的方法来验证这些字段,我可以实施以确保我们的网站用户有很好的体验,并且在列表中注册时可以实际使用他们的名字

我会寻找类似于您可以在谷歌上找到的许多“电子邮件地址”正则表达式的东西。

4

13 回答 13

44

我同情在这种情况下需要限制输入,但我不相信这是可能的——Unicode 是巨大的、不断扩展的,世界各地名称中使用的子集也是如此。

与电子邮件不同,对于人们可以使用的名称,甚至他们可以在各自政府注册为官方的表示形式,没有普遍认可的标准。我怀疑任何正则表达式最终都无法通过世界某处某人认为有效的名称。

当然,您确实需要清理或转义输入,以避免Little Bobby Tables问题。对于您允许的输入可能还有其他限制,例如用于存储、呈现或操作名称的底层系统。因此,我建议您首先确定您的验证所属系统所需的限制,并仅基于这些限制创建验证表达式。在某些情况下,这可能仍会造成不便,但应该很少见。

于 2009-05-20T16:12:24.007 回答
16

我会尝试自己给出一个正确的答案:

名称中唯一应该允许的标点符号是句号、撇号和连字符。我在极端案例列表中没有看到任何其他案例。

关于数字,只有一种情况是 8。我想我可以放心地拒绝这种情况。

关于信件,任何信件都是有效的。

我也想包括空间。

这将总结为这个正则表达式:

^[\p{L} \.'\-]+$

这提出了一个问题,即撇号可以用作攻击向量。它应该被编码。

所以验证代码应该是这样的(未经测试):

var name = nameParam.Trim();
if (!Regex.IsMatch(name, "^[\p{L} \.\-]+$")) 
    throw new ArgumentException("nameParam");
name = name.Replace("'", "'");  //' does not work in IE

谁能想到一个名字不应该通过这个测试的原因,或者一个可以通过的 XSS 或 SQL 注入?


完整的测试解决方案

using System;
using System.Text.RegularExpressions;

namespace test
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            var names = new string[]{"Hello World", 
                "John",
                "João",
                "タロウ",
                "やまだ",
                "山田",
                "先生",
                "мыхаыл",
                "Θεοκλεια",
                "आकाङ्क्षा",
                "علاء الدين",
                "אַבְרָהָם",
                "മലയാളം",
                "상",
                "D'Addario",
                "John-Doe",
                "P.A.M.",
                "' --",
                "<xss>",
                "\""
            };
            foreach (var nameParam in names)
            {
                Console.Write(nameParam+" ");
                var name = nameParam.Trim();
                if (!Regex.IsMatch(name, @"^[\p{L}\p{M}' \.\-]+$"))
                {
                    Console.WriteLine("fail");
                    continue;
                }
                name = name.Replace("'", "&#39;");
                Console.WriteLine(name);
            }
        }
    }
}
于 2009-05-20T19:03:21.150 回答
15

我只会允许所有内容(空字符串除外)并假设用户知道他的名字是什么。

有2种常见情况:

  1. 您关心姓名是否准确,并根据真实的纸质护照或其他身份证件或信用卡进行验证。
  2. 您并不在意,用户无论如何都可以注册为“Fred Smith”(或“Jane Doe”)。

在情况 (1) 中,您可以允许所有字符,因为您正在检查纸质文档。

在情况 (2) 中,您也可以允许所有字符,因为“123 456”实际上并不比“Abc Def”更差。

于 2009-05-20T16:13:13.723 回答
13

我认为你最好用正则表达式排除你不想要的字符。试图让每个变音符号、重音 e、连字符等都变得非常疯狂。只需排除数字(但是一个名叫“乔治·福曼四世”的人呢)和你知道你不想要的符号,比如@#$%^ 或者你有什么。但即便如此,使用正则表达式也只能保证输入与正则表达式匹配,它不会告诉你它是一个有效的名称。

在澄清这是试图防止 XSS 后编辑:名称字段上的正则表达式显然不会自行停止 XSS。但是,如果您想走这条路,本文有一个关于过滤的部分是一个起点:

s/[\<\>\"\'\%\;\(\)\&\+]//g;

David A. Wheeler 的“Linux 和 Unix 安全编程 HOWTO”,v3.010 版 (2003)

v3.72, 2015-09-19是更新的版本。

于 2009-05-20T16:09:13.247 回答
7

顺便说一句,您打算只允许拉丁字母,还是还打算尝试验证中文、阿拉伯语、印地语等?

正如其他人所说,甚至不要尝试这样做。退后一步,问问自己你真正想要完成什么。然后尝试在不对人们的名字是什么或他们的意思做任何假设的情况下完成它。

于 2009-05-20T16:18:10.953 回答
6

我不认为这是个好主意。即使您找到了合适的正则表达式(可能使用 Unicode 字符属性),这也不会阻止用户输入像John DoeMax Mustermann(甚至有人使用该名称)、Abcde FghijkAbaba Bebebe这样的伪名称。

于 2009-05-20T16:13:55.330 回答
5

您可以使用以下正则表达式代码来验证 2 个由空格分隔的名称,并使用以下正则表达式代码:

^[A-Za-zÀ-ú]+ [A-Za-zÀ-ú]+$

或者只是使用:

[[:lower:]] = [a-zà-ú]

[[:upper:]] =[A-ZÀ-Ú]

[[:alpha:]] = [A-Za-zÀ-ú]

[[:alnum:]] = [A-Za-zÀ-ú0-9]

于 2012-04-08T00:29:28.607 回答
2

由于所有可能的极端情况,验证名称之类的东西是一个非常困难的问题。

角落案例

清理输入并让他们输入任何他们想要的名称,因为确定什么是有效名称,什么不是可能超出您正在做的任何事情的范围;鉴于潜在的奇怪和合法名称的范围几乎是无限的。

如果他们想称自己为 Tricyclopltz^2-Glockenschpiel,那是他们的问题,而不是你的问题。

于 2009-05-20T17:35:55.490 回答
2

我似乎在这里偶然发现了一个非常有争议的主题。然而,有时在通行证上带走亲爱的小鲍比桌子并将小罗伯特连同他的分号和 SQL 注释行一起送到校长办公室是件好事——。

VB.NET 中的这个 REGEX 包括常规字母字符和各种转折欧洲字符。然而,可怜的老詹姆斯麦克特里斯坦-史密斯三世将不得不输入他的血统书作为吉姆三世。

<asp:RegularExpressionValidator ID="RegExValid1" Runat="server"
                    ErrorMessage="ERROR: Please enter a valid surname<br/>" SetFocusOnError="true" Display="Dynamic"
                    ControlToValidate="txtSurname" ValidationGroup="MandatoryContent"
                    ValidationExpression="^[A-Za-z'\-\p{L}\p{Zs}\p{Lu}\p{Ll}\']+$">
于 2011-05-05T10:16:38.903 回答
2

这个在 JavaScript 中非常适合我: ^[a-zA-Z]+[\s|-]?[a-zA-Z]+[\s|-]?[a-zA-Z]+$

这是方法:

function isValidName(name) {
    var found = name.search(/^[a-zA-Z]+[\s|-]?[a-zA-Z]+[\s|-]?[a-zA-Z]+$/);
    return found > -1;
}
于 2019-04-28T05:39:57.670 回答
0

脚步:

  1. 首先删除所有重音
  2. 应用正则表达式

去除重音:

private static string RemoveAccents(string s)
{
    s = s.Normalize(NormalizationForm.FormD);
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < s.Length; i++)
    {
        if (CharUnicodeInfo.GetUnicodeCategory(s[i]) != UnicodeCategory.NonSpacingMark) sb.Append(s[i]);
    }
    return sb.ToString();
}
于 2016-08-20T12:15:45.360 回答
-2

这有点帮助:

^[a-zA-Z]'?([a-zA-Z]|\.| |-)+$

于 2012-06-28T00:23:41.933 回答
-3

^([A-Z]{1}+[a-z\-\.\']*+[\s]?)* 如果需要,这个应该可以 添加一些特殊字符。

于 2016-03-10T07:45:58.240 回答