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
这里只剩下一个分组,(?:...)
,可选,后面的?
让它匹配1次或者0次
详情
[\p{L}'-]{2,}
- 2 个或更多字母,'
或 -
(?:\s[\p{L}'-]+)?
- 出现 1 次或 0 次空格,然后出现 1 个或多个字母,'
或 -
\s
- 一个空格
[\p{L}'-]{2,}
- 2 个或更多字母,'
或 -
我正在使用这个 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
这里只剩下一个分组,(?:...)
,可选,后面的?
让它匹配1次或者0次
详情
[\p{L}'-]{2,}
- 2 个或更多字母,'
或-
(?:\s[\p{L}'-]+)?
- 出现 1 次或 0 次空格,然后出现 1 个或多个字母,'
或-
\s
- 一个空格[\p{L}'-]{2,}
- 2 个或更多字母,'
或-