Regex для имен со специальными символами (Unicode) - PullRequest
11 голосов
/ 11 мая 2011

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

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

Примером принятого имени будет: «Джон Элкьорд» или «Андре Свенсон»Неприемлемое имя будет: " Ганс ", "H 4 nn 3 Андерсен" или "Мартин Хенриксен ! "

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

Любая помощь будет принята с благодарностью.

Обновление: Хорошо, благодаря ответу Аликс Аксель У меня есть важная часть, серверная часть.

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

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

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

Ответы [ 7 ]

29 голосов
/ 11 мая 2011

Попробуйте следующее регулярное выражение:

^(?:[\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

Iчестно говоря, не знаю, как перенести это в 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, но, возможно, кто-то здесь поможет.


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

  • Джон Элкьярд
  • Андре Свенсон
  • Марко д'Альмейда
  • Кристоффер ла Кур

Недействительно :

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

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

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

Примеры:

  • H4nn3 Андерсен -> Гнн Андерсен
  • Martin Henriksen! -> Martin Henriksen

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

5 голосов
/ 15 апреля 2013

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

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

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

2 голосов
/ 05 июня 2013

Вот оптимизация по поводу фантастического ответа @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" не будет совпадать.


Наконец, поскольку я нашел этот вопрос, когда искал похожее решение для , вот регулярное выражение asиспользоваться в Ruby 1.9 +

\A(?:[\p{L}\p{Mn}\p{Pd}\'\U+2019]+(?:\Z|\s+)){2,}\Z

Основными изменениями являются использование \ A и \ Z для начала и конца строки (вместо строки) и символьная нотация Ruby Unicode.

2 голосов
/ 11 мая 2011

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

пример:

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

EDIT:

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

[a-zA-ZßöäüÖÄÜæé]+\s[a-zA-ZßöäüÖÄÜæé]+
2 голосов
/ 11 мая 2011
0 голосов
/ 16 мая 2017

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

^([a-zA-Z\xC0-\uFFFF]{1,60}[ \-\']{0,1}){1,3}$
0 голосов
/ 11 мая 2011

При проверке входной строки вы можете

  • обрезать () ее, чтобы удалить начальные / конечные пробелы
  • совпадение с [^ \ w \ s] для обнаружения не слова \непробельные символы
  • совпадают с \ s +, чтобы получить количество разделителей слов, равное количеству слов + 1.

Однако я не уверен, что сокращение \ wсодержит акцентированные символы, но они должны попадать в категорию «словесные символы».

...