preg_match first/last 名称匹配组

preg_match first/last name matching groups

我正在使用这个 PHP 正则表达式来检查 true/false 字段是否包含名称,至少包含一个 first/last 名称,然后是可选的其他中间名或首字母.

$success = preg_match("/([\x{00c0}-\x{01ff}a-zA-Z'-]){2,}(\s([\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})/ui",$user['name'],$matches);

$output[($success ? 'hits' : 'misses')][] = ['id' => $user['id'],'email' => $user['email'],'name' => $user['name'],'matches' => $matches];

似乎在 hits/misses 方面工作正常,即 true/false 无论匹配与否。

但后来我尝试使用相同的方法使用组提取名字和姓氏,我正在努力做到这一点..

获得大量结果,例如:

  "name": "Jonny Nott",
  "matches": [
    "Jonny Nott",
    "y",
    "",
    "",
    "Nott"
  ]

  "name": "Name Here",
  "matches": [
    "Name Here",
    "e",
    "",
    "",
    "Here"
  ]

  "matches": [
    "Jonathan M Notty",
    "n",
    " M",
    "M",
    "Notty"
  ]

..但我真正想要的是 'matches' 中的一个始终仅包含名字,而另一个始终仅包含姓氏。

有什么地方出了问题吗?

尝试:

(?P<firstName>[\x{00c0}-\x{01ff}a-zA-Z'-]{2,})(\s([\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s(?P<lastName>[\x{00c0}-\x{01ff}a-zA-Z'-]{2,})

您的主要错误是重复第一组 {2,} - 不是第一范围

每当您必须使用括号但又不想匹配该部分(例如,部分空格和中间名)并在捕获组中包含量词时,请使用非捕获组 (?:...),不仅要匹配的字符(例如,名字 {2,} 应该在捕获组中)。

([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})(?:\s(?:[\x{00c0}-\x{01ff}a-zA-Z'-]{1,})*)?\s([\x{00c0}-\x{01ff}a-zA-Z'-]{2,})

每当您在正则表达式中定义 capturing group 时,它匹配的字符串部分将作为单独的项目添加到结果数组中。有两种策略可以摆脱它们:

  • 优化模式并去除冗余组(例如围绕单个原子的组 - (a)+ => a+
  • 将捕获组变为 non-capturing ((\s+\w+)+ => (?:\s+\w+)+)

此外,在您的情况下,如果将字母匹配部分替换为匹配任何字母的 \p{L} Unicode 属性 class,则可能会增强模式。

使用

/[\p{L}'-]{2,}(?:\s[\p{L}'-]+)?\s[\p{L}'-]{2,}/u

regex demo

这里只剩下一个分组,(?:...),可选,后面的?让它匹配1次或者0次

详情

  • [\p{L}'-]{2,} - 2 个或更多字母,'-
  • (?:\s[\p{L}'-]+)? - 出现 1 次或 0 次空格,然后出现 1 个或多个字母,'-
  • \s - 一个空格
  • [\p{L}'-]{2,} - 2 个或更多字母,'-