带有特殊字符的名称的正则表达式 (Unicode)

IT技术 php javascript regex character-properties
2021-02-28 09:53:33

好的,我已经读了一整天关于正则表达式的内容,但仍然没有正确理解它。我想要做的是验证一个名称,但我在互联网上可以找到的功能只使用[a-zA-Z],而忽略了我需要接受的字符。

我基本上需要一个正则表达式来检查名称是否至少是两个单词,并且它不包含数字或特殊字符,例如!"#¤%&/()=...,但是单词可以包含 æ、é、Â 等字符...

可接受名称的示例是:“John Elkjærd”或“André Svenson”
不被接受的名称是:“ Hans ”、“H 4 nn 3 Andersen”或“Martin Henriksen

如果重要的话,我使用 javascript.match()函数客户端并想使用 phppreg_replace()唯一的“负面”服务器端。(删除不匹配的字符)。

任何帮助将非常感激。

更新:
好的,感谢Alix Axel 的回答,我有重要的部分,服务器端。

但是正如LightWing 回答中的页面所暗示的那样,我无法找到有关 Unicode 对 javascript 支持的任何信息,因此我最终为客户端找到了一半解决方案,只需检查至少两个单词和至少 5 个字符,如下所示:

if(name.match(/\S+/g).length >= minWords && name.length >= 5) {
  //valid
}

另一种方法是按照shifty 的回答中的建议指定所有 unicode 字符,我最终可能会做类似的事情,以及上面的解决方案,但这有点不切实际。

6个回答

试试下面的正则表达式:

^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s?)+$

在 PHP 中,这转化为:

if (preg_match('~^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s?)+$~u', $name) > 0)
{
    // valid
}

你应该这样读:

^   # start of subject
    (?:     # match this:
        [           # match a:
            \p{L}       # Unicode letter, or
            \p{Mn}      # Unicode accents, or
            \p{Pd}      # Unicode hyphens, or
            \'          # single quote, or
            \x{2019}    # single quote (alternative)
        ]+              # one or more times
        \s          # any kind of space
        [               #match a:
            \p{L}       # Unicode letter, or
            \p{Mn}      # Unicode accents, or
            \p{Pd}      # Unicode hyphens, or
            \'          # single quote, or
            \x{2019}    # single quote (alternative)
        ]+              # one or more times
        \s?         # any kind of space (0 or more times)
    )+      # one or more times
$   # end of subject

老实说,我不知道如何将它移植到 Javascript,我什至不确定 Javascript 是否支持 Unicode 属性,但在 PHP PCRE 中,这似乎完美无缺@IDEOne.com

$names = array
(
    'Alix',
    'André Svenson',
    'H4nn3 Andersen',
    'Hans',
    'John Elkjærd',
    'Kristoffer la Cour',
    'Marco d\'Almeida',
    'Martin Henriksen!',
);

foreach ($names as $name)
{
    echo sprintf('%s is %s' . "\n", $name, (preg_match('~^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s?)+$~u', $name) > 0) ? 'valid' : 'invalid');
}

很抱歉,关于 Javascript 部分我无法帮助您,但这里可能有人会帮助您。


验证

  • 约翰·埃尔克亚德
  • 安德烈·斯文森
  • 马可·德阿尔梅达
  • 克里斯托弗拉库尔

无效

  • 汉斯
  • H4nn3安徒生
  • 马丁·亨利克森!

要替换无效字符,虽然我不确定您为什么需要它,但您只需要稍微更改它:

$name = preg_replace('~[^\p{L}\p{Mn}\p{Pd}\'\x{2019}\s]~u', '$1', $name);

例子:

  • H4nn3 安徒生-> Hnn 安徒生
  • 马丁·亨利克森!->马丁·亨利克森

请注意,您始终需要使用u修饰符。

@AlixAxel。截至 2019 年 3 月 11 日,js 在浏览器中仍然是 Unicode 愚蠢的。正如您所建议的,如果想在进行时进行验证,请使用 AJAX,否则使用该pattern属性来拒绝主要不需要的代码,然后在服务器上进行完全验证。
2021-04-17 09:53:33
对正则表达式部分的解释很棒,给我的不仅仅是盲目的复制粘贴。JS 仍然给我带来麻烦,但是当/如果我找到解决方案时,我会将其发布到此处。
2021-04-25 09:53:33
没有找到很好的 JS 解决方案,但我最终按照我更新问题中的描述做了。
2021-04-25 09:53:33
@Kristoffer:我已经更新了我的问题以更好地解释正则表达式,如果没有其他 JS 替代方案,您始终可以使用 Ajax 并调用 PHP 来验证它。
2021-05-07 09:53:33
感谢您的回答,这是完美的!我现在只需要让它与 js 一起工作,但这并不难,现在我至少有一些东西可以做。:) 哦,我想删除无效字符的原因是为了避免诸如“Tamperdata”或“cURL”之类的东西给我错误的输入,但如果我也验证了,我想这没有意义:) 再次感谢。
2021-05-15 09:53:33

关于 JavaScript,它更棘手,因为 JavaScript Regex 语法不支持 unicode 字符属性。一个务实的解决方案是匹配这样的字母:

[a-zA-Z\xC0-\uFFFF]

这允许使用所有语言的字母,但不包括数字和键盘上常见的所有特殊(非字母)字符。它是不完美的,因为它还允许非字母的 unicode 特殊符号,例如表情符号、雪人等。然而,由于这些符号在键盘上通常不可用,我认为它们不会被意外输入。因此,根据您的要求,它可能是一个可以接受的解决方案。

谢谢。我正在寻找这个,因为上面的 RegEx 在客户端 JavaScript 验证中不起作用......我最终得到了这个: public const string NameFull = @"^(?!.{52,})[a-zA-Z\ xC0-\uFFFF\.\'\-]{2,50}(?: [a-zA-Z\xC0-\uFFFF\.\'\-]{2,50})+$"; 然后验证表情符号:regex101.com/r/jP5jC5/2
2021-04-26 09:53:33
谢谢,确实有助于理解它。
2021-04-17 09:53:33

您可以将允许的特殊字符添加到正则表达式中。

例子:

[a-zA-ZßöäüÖÄÜæé]+

编辑:

不是最好的解决方案,但如果至少有文字,这将给出结果。

[a-zA-ZßöäüÖÄÜæé]+\s[a-zA-ZßöäüÖÄÜæé]+
@Alis:\s 更好。谢谢你的建议。我不是正则专家:D
2021-04-16 09:53:33
为什么[ \t]而不只是\s
2021-05-02 09:53:33

这是对上面@Alix 出色答案的优化。它消除了两次定义字符类的需要,并允许更容易地定义任意数量的必需单词。

^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+(?:$|\s+)){2,}$

它可以分解如下:

^         # start
  (?:       # non-capturing group
    [         # match a:
      \p{L}     # Unicode letter, or
      \p{Mn}    # Unicode accents, or
      \p{Pd}    # Unicode hyphens, or
      \'        # single quote, or
      \x{2019}  # single quote (alternative)
    ]+        # one or more times
    (?:       # non-capturing group
      $         # either end-of-string
    |         # or
      \s+       # one or more spaces
    )         # end of group
  ){2,}     # two or more times
$         # end-of-string

本质上,它是说找到一个由字符类定义的单词,然后找到一个或多个空格或一行的结尾。{2,}在年底告诉它最低的两个词必须找到一个匹配成功。这可确保 OP 的“Hans”示例不匹配。


最后,因为我在寻找类似的解决方案时发现了这个问题 , 这是可以在 Ruby 1.9+ 中使用的正则表达式

\A(?:[\p{L}\p{Mn}\p{Pd}\'\U+2019]+(?:\Z|\s+)){2,}\Z

主要的变化是使用 \A 和 \Z 作为字符串的开头和结尾(而不是行)和 Ruby 的 Unicode 字符表示法。