Regex для имен со специальными символами (Unicode)

Хорошо, я читал о regex весь день и все еще не понимаю его правильно. То, что я пытаюсь сделать, это проверить имя, но функции, которые я могу найти для этого в Интернете, используют только [a-zA-Z], оставляя символы, которые мне нужно принять.

Мне в основном нужно регулярное выражение, которое проверяет, что имя не менее двух слов, и что оно не содержит чисел или специальных символов, таких как !"#¤%&/()=..., однако слова могут содержать символы, такие как æ, é, Â и т.д...

Примером принятого имени будет: "John Elkjærd" или "André Svenson"
Непринятое имя будет:" Hans "," H 4 nn 3 Андерсен "или" Мартин Хенриксен ! "

Если это важно, я использую клиентскую часть функции javascript .match() и хочу использовать только php preg_replace() только на отрицательной стороне сервера. (удаление несоответствующих символов).

Любая помощь будет высоко оценена.

Обновление:
Хорошо, спасибо Alix Axel answer У меня есть важная часть вниз, на стороне сервера.

Но поскольку страница из LightWing отвечает, я не могу найти что-либо о поддержке юникода для javascript, поэтому у меня оказалось половина решения для клиента стороне, просто проверяя хотя бы два слова и минимум 5 символов:

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

Альтернативой было бы указать все символы Юникода, как предложено в переменном ответе, в результате чего я мог бы сделать что-то вроде этого вместе с решением выше, но это хотя и непрактичен.

Ответ 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 этот работает безупречно @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, но, вероятно, кто-то здесь будет.


Подтверждает

  • John Elkjærd
  • Андре Свенсон
  • Марко д'Альмейда
  • Kristoffer la Cour

недействительными

  • Ганс
  • H4nn3 Andersen
  • Мартин Хенриксен!

Чтобы заменить недопустимые символы, хотя я не уверен, зачем вам это нужно, вам просто нужно немного его изменить:

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

Примеры:

  • H4nn3 Andersen Hnn Andersen
  • Мартин Хенриксен! Мартин Хенриксен

Обратите внимание, что вам всегда нужно использовать модификатор u.

Ответ 3

вы можете добавить разрешенные специальные символы в регулярное выражение.

Пример:

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

EDIT:

не лучшее решение, но это даст результат, если есть хотя бы слова.

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

Ответ 4

Что касается JavaScript, это более сложно, так как синтаксис JavaScript Regex не поддерживает свойства символа Юникода. Прагматичным решением было бы сопоставление букв следующим образом:

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

Это позволяет писать буквы на всех языках и исключает числа и все специальные (небуквенные) символы, обычно встречающиеся на клавиатурах. Это несовершенно, поскольку он также позволяет использовать специальные символы unicode, которые не являются буквами, например. смайлики, снеговик и так далее. Однако, поскольку эти символы, как правило, недоступны на клавиатурах, я не думаю, что они будут введены случайно. Поэтому в зависимости от ваших требований это может быть приемлемым решением.

Ответ 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 содержит акцентированные символы, но оно должно попадать в категорию "слова".

Ответ 7

Это регулярное выражение JS, которое я использую для причудливых имен, составленных с максимальным количеством слов (от 1 до 60 символов), разделенных знаком пространства/одиночной кавычки/минуса

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