2011-05-11 59 views
11

Bien, he leído sobre regex todo el día y todavía no lo entiendo correctamente. Lo que trato de hacer es validar un nombre, pero las funciones que puedo encontrar para esto en internet solo usan [a-zA-Z], dejando los caracteres que necesito aceptar.Regex para nombres con caracteres especiales (Unicode)

Básicamente necesito una expresión regular que compruebe que el nombre sea de al menos dos palabras, y que no contenga números o caracteres especiales como !"#¤%&/()=..., pero las palabras pueden contener caracteres como æ, é, Â, etc. .

un ejemplo de un nombre aceptado sería: "John Elkjærd" o "André Svenson"
un nombre no aceptado sería: "Hans", "H nn Andersen" o "Martin Henriksen !"

Si importa, uso el lado del cliente de la función javascript .match() y quiero usar el preg_replace() de php solo del lado del servidor "negativo". (eliminando los caracteres que no coinciden).

Cualquier ayuda sería muy apreciada.

Actualizar:
bien, gracias a Alix Axel's answer i tienen el importante papel hacia abajo, el lado del servidor uno.

Pero como la página de LightWing's answer sugiere, no puedo encontrar nada acerca del soporte de unicode para javascript, así que terminé con la mitad de una solución para el lado del cliente, solo revisando al menos dos palabras y un mínimo de 5 caracteres como esto:

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

una alternativa sería especificar todos los caracteres Unicode como se sugiere en shifty's answer, que podría terminar haciendo algo así, junto con la solución anterior, pero es un poco poco práctico sin embargo.

+0

puede elaborarla con el ejemplo –

+0

@ Amit Gupta, gracias, lo hice. :) –

Respuesta

29

Prueba la siguiente expresión regular:

^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+\s?)+$ 

En PHP Esto se traduce en:

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 
} 

es preferible hacerlo de esta manera:

^ # 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 

Sinceramente, Don No sé cómo portar esto a Javas cripta, ni siquiera estoy seguro de Javascript admite propiedades Unicode, pero en PHP PCRE este seems to work flawlessly @ 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'); 
} 

Lo siento, no puedo ayudarle con respecto a la parte Javascript pero probablemente alguien aquí será.


Valida:

  • John Elkjærd
  • André Svenson
  • Marco d'Almeida
  • Kristoffer la Cour

Inva lidates:

  • Hans
  • H4nn3 Andersen
  • Martin Henriksen!

Para reemplazar caracteres no válidos, aunque no estoy seguro de por qué es necesario esto, sólo tiene que cambiar ligeramente:

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

Ejemplos:

  • H4nn3 Andersen -> Hnn Andersen
  • Martin Henriksen! -> Martin Henriksen

en cuenta que siempre es necesario utilizar el modificador u .

+0

Gracias por la respuesta, ¡esto es perfecto! solo necesito hacer que funcione con js ahora, pero no puede ser difícil, ahora al menos tengo algo de qué ir. :) Ohh, y la razón por la que quiero eliminar los caracteres no válidos es evitar algo como "Tamperdata" o "cURL" para darme una entrada incorrecta, pero si valido también creo que no tiene sentido :) Nuevamente, gracias. –

+0

@Kristoffer: He actualizado mi pregunta para explicar mejor la expresión regular, si no hay otra alternativa de JS, siempre puedes usar Ajax y llamar a PHP para validarla. –

+0

la explicación de las partes de la expresión regular es excelente, me ofrece algo más que un simple copiar y pegar ciegamente. JS todavía me está causando problemas, pero cuando/si encuentro una solución, la publicaré aquí. –

2

puede agregar los caracteres especiales se permite la expresión regular.

ejemplo:

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

EDIT:

no es la mejor solución, pero esto daría un resultado si hay por lo menos a las palabras.

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

¿Por qué '[\ t]' y no solo '\ s'? –

+0

No, no es perfecto, pero es una opción, gracias de todos modos. :) –

+2

@Alis: \ s es mejor. gracias por el consejo. No soy un regexpert: D – superbly

0

Cuando el control de su cadena de entrada se podía

  • trim() para eliminar líder/arrastrando espacios en blanco
  • partido contra [^ \ w \ s] para detectar la no-palabra \ caracteres no está en blanco
  • coinciden con \ s + para obtener el número de separadores de palabras que es igual al número de palabras + 1.

Sin embargo no estoy seguro de que el \ w abreviada incluye caracteres acentuados, pero debería caer en la categoría "caracteres de palabra".

+0

'\ w' es equivalente a' [0-9a-zA-Z_] ', dependiendo de la configuración regional específica de la máquina esto podría (no) funcionar con caracteres acentuados/unicode, de cualquier forma siempre coincidirá con los dígitos, y no debería ' t. –

+0

oh, parece que tendré que arreglar muchos trozos de mi propio código :(¡gracias por la información valiosa! – ashein

2

En cuanto a JavaScript, es más complicado, ya que la sintaxis de JavaScript Regex no admite propiedades de caracteres Unicode. Una solución práctica sería para que coincida con las letras de esta manera:

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

Esto permite letras en todos los idiomas y números excluye y todos los caracteres especiales (no letras) se encuentran comúnmente en los teclados. Es imperfecto porque también permite símbolos especiales unicode que no son letras, p. emoticones, muñeco de nieve, etc. Sin embargo, dado que estos símbolos generalmente no están disponibles en los teclados, no creo que se ingresen por accidente. Por lo tanto, dependiendo de sus requisitos, puede ser una solución aceptable.

+0

Gracias. Estaba buscando esto porque el RegEx anterior no funciona en la validación de JavaScript del lado del cliente ... terminó con esto: public const string NameFull = @ "^ (?!. {52,}) [a-zA-Z \ xC0- \ uFFFF \. \ '\ -] {2,50} (?: [a -zA-Z \ xC0- \ uFFFF \. \ '\ -] {2,50}) + $ "y validando para Emoji después: https://regex101.com/r/jP5jC5/2 – Yovav

2

Aquí hay una optimización de la fantástica respuesta de @Alix anterior. Elimina la necesidad de definir la clase de caracteres dos veces, y permite una definición más fácil de cualquier número de palabras requeridas.

^(?:[\p{L}\p{Mn}\p{Pd}\'\x{2019}]+(?:$|\s+)){2,}$ 

Se puede desglosarse de la siguiente manera:

^   # 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 

En esencia, se está diciendo que encontrar una palabra como se define por la clase de caracteres, entonces o bien encontrar uno o más espacios o un extremo de una línea. El {2,} al final le dice que se debe encontrar un mínimo de dos palabras para que una coincidencia tenga éxito. Esto asegura que el ejemplo "Hans" de OP no coincidirá.


Por último, desde que encontré esta pregunta mientras se busca una solución similar para , aquí es la expresión regular que se puede utilizar en Rubí 1.9+

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

Los principales cambios están utilizando \ A y \ Z para el comienzo y el final de la cadena (en lugar de la línea) y la notación de caracteres Unicode de Ruby.

0

Ésta es la expresión regular JS que yo uso para nombres de fantasía compuestas con 3 palabras como máximo (de 1 a 60 caracteres), separados por la muestra del espacio/comilla simple/menos

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