Совместить только набор символов с одного языка (например, имя facebook)?

preg_match(???, 'firstname lastname') // true;
preg_match(???, '서프 누워') // true;
preg_match(???, '서프 lastname') // false;
preg_match(???, '#[email protected] #$$#') // false;

В настоящее время я использую:

'/^([一-龠0-9\s]+|[ぁ-ゔ0-9\s]+|[ก-๙0-9\s]+|[ァ-ヴー0-9\s]+|[a-zA-Z0-9\s]+|[々〆〤0-9\s]+)$/u'

Но он работает только на некоторых языках.

Ответ 1

Вам нужно выражение, которое будет соответствовать только символам из тех же unicode script (и пробелов), например:

 ^([\p{SomeScript} ]+|[\p{SomeOtherScript} ]+|...)$

Вы можете построить это выражение динамически из списка скриптов:

$scripts = "Hangul Hiragana Han Latin Cyrillic"; // feel free to add more

$re = [];
foreach(explode(' ', $scripts) as $s)
    $re [] = sprintf('[\p{%s} ]+', $s);
$re = "~^(" . implode("|", $re) . ")$~u";

print preg_match($re, 'firstname lastname'); // 1
print preg_match($re, '서프 누워'); // 1
print preg_match($re, '서프 lastname'); // 0
print preg_match($re, '#[email protected] #$$#'); // 0

Обратите внимание, что это общепринято для имен (по крайней мере, в европейских сценариях, с которыми я знаком), чтобы включать символы, такие как точки, тире и апострофы, которые относятся к "Common" script, а не к языку -специфический. Чтобы принять это во внимание, более реалистичная версия "куска" в приведенном выше выражении может быть примерно такой:

 ((\p{SomeScript}+(\. ?|[ '-]))*\p{SomeScript}+)

который будет хотя бы корректно проверять L. A. Léon de Saint-Just.

В целом, проверка имен людей является сложной проблемой и не может быть решена с точностью 100%. См. этот смешной пост и комментарии к нему для деталей и примеров.