【问题标题】:Regex for names with special characters (Unicode)带有特殊字符的名称的正则表达式 (Unicode)
【发布时间】:2011-08-23 05:21:11
【问题描述】:

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

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

一个被接受的名字的例子是:“John Elkjærd”或“André Svenson”
一个不被接受的名字是:“Hans”、“H4nn3 安徒生”或“马丁·亨利克森

如果这很重要,我使用 javascript .match() 函数客户端并希望仅在“负面”服务器端使用 php 的 preg_replace()。 (删除不匹配的字符)。

任何帮助将不胜感激。

更新:
好的,感谢Alix Axel's answer 我已经完成了重要的部分,服务器端的部分。

但正如LightWing's answer 的页面所暗示的那样,我找不到任何关于 javascript 的 unicode 支持的信息,所以我最终为客户端提供了一半的解决方案,只需检查至少两个单词和至少 5 个字符像这样:

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

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

【问题讨论】:

  • 你能举例说明一下吗
  • @Amit Gupta,谢谢,我做到了。 :)

标签: php javascript regex character-properties


【解决方案1】:

试试下面的正则表达式:

^(?:[\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 中,seems to work flawlessly @ 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 Andersen -> Hnn Andersen
  • 马丁·亨利克森! ->马丁·亨里克森

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

【讨论】:

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

关于 JavaScript,它更棘手,因为 JavaScript 正则表达式语法不支持 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})+$";并在之后验证 Emoji:regex101.com/r/jP5jC5/2
【解决方案3】:

【讨论】:

  • 谢谢,确实有助于理解。
【解决方案4】:

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

示例:

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

编辑:

不是最好的解决方案,但如果至少有单词的话,这会给出一个结果。

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

【讨论】:

  • 为什么是[ \t] 而不仅仅是\s
  • @Alis: \s 更好。谢谢你的建议。我不是正则专家:D
【解决方案5】:

这是对上面@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 字符表示法。

【讨论】:

    【解决方案6】:

    当检查你的输入字符串时,你可以

    • trim() 删除前导/尾随空格
    • 匹配 [^\w\s] 以检测非单词\非空白字符
    • 匹配 \s+ 得到单词分隔符的数量等于单词数+1。

    但是我不确定 \w 速记是否包含重音字符,但它应该属于“单词字符”类别。

    【讨论】:

    • \w 等价于[0-9a-zA-Z_],取决于特定的机器语言环境,这可能(不)与重音/unicode 字符一起使用,无论哪种方式,它都将始终匹配数字,它不应该。
    • 哦,看来我得去修复我自己的许多代码块了 :( 感谢提供有价值的信息!
    【解决方案7】:

    这是我用于由最多 3 个单词(1 到 60 个字符)组成的花哨名称的 JS 正则表达式,由空格/单引号/减号分隔

    ^([a-zA-Z\xC0-\uFFFF]{1,60}[ \-\']{0,1}){1,3}$
    

    【讨论】:

      猜你喜欢
      • 2011-02-20
      • 2022-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-30
      相关资源
      最近更新 更多