2009-12-18 8 views
17

ya estoy consciente de que \w en PCRE (en particular la aplicación de PHP) a veces puede coincidir con algunos caracteres no ASCII en función de la configuración regional del sistema, pero ¿qué pasa con [a-z]?¿[a-z] alguna vez coincidirá con los caracteres acentuados en PREG/PCRE?

yo no lo creo, pero me di cuenta de estas líneas en uno de los archivos de núcleo de Drupal (includes/theme.inc, simplificada):

// To avoid illegal characters in the class, 
// we're removing everything disallowed. We are not using 'a-z' as that might leave 
// in certain international characters (e.g. German umlauts). 
$body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', $class); 

es esto cierto, o alguien simplemente obtener [a-z] confusa con \w?

Respuesta

13

Larga historia corta: Tal vez, depende del sistema de la aplicación se implementa en, depende de cómo se compila PHP, bienvenido a la CF de localización e internacionalización.

El motor PCRE subyacente toma locale en cuenta al determinar qué "a-z" significa. En un local con base en español, ñ sería atrapado por a-z). El significado semántico de az es "todas las cartas entre A y Z, y N es una carta por separado en español.

Sin embargo, la forma en PHP maneja ciegamente cadenas como colecciones de bytes en lugar de una colección de puntos de código UTF significa que tiene una situación donde AZ PODRÍA coincidir con un carácter acentuado. Dada la variedad de diferentes sistemas en los que se implementa Drupal, tiene sentido que opten por ser explícitos sobre los caracteres permitidos en lugar de simplemente confiar en que az haga lo correcto.

También conjeturo que la existencia de esta expresión regular es el resultado de un informe de error que se archiva sobre diéresis de alemán no se filtran.

actualización en 2014: Por JimmiTh's answer below, parece que (a pesar de una cierta documentación "-pcre-core-developers-confusos-a no") que [a-z] sólo igualará los personajes abcdefghijklmnopqrstuvwxyz un proverbiales 99% de las veces . Dicho esto, los desarrolladores de frameworks tienden a mostrarse inquietos sobre la vaguedad en su código, especialmente cuando el código se basa en sistemas (cadenas locales específicas) que PHP no maneja tan elegantemente como quisieras, y servidores sobre los que los desarrolladores no tienen control. Mientras que los comentarios del desarrollador anónimo de Drupal son incorrectos, no se trataba de "obtener [a-z] confundido con \w", sino que un desarrollador de Drupal no estaba seguro/claro de cómo PCRE manejaba [a-z], y elegir la forma más específica de abcdefghijklmnopqrstuvwxyz para asegurar el comportamiento específico que ellos querían.

+0

¿Fue esto realmente cierto en 2009? –

+0

@WalterTross Sigue siendo tan cierto hoy como lo era en aquel entonces. Nunca se trata de lo que era/es común, se trata de lo que PODRÍA suceder con alguna configuración extraña, y de asegurarse de que su código sea lo suficientemente robusto como para manejarlo. –

+1

@ AlanStorm, ¿puede proporcionar una configuración tan extraña? ¡Estoy bastante seguro de que no hay ninguno! –

10

El comentario en el código de Drupal es ERROR.

Es NOT cierto que "international characters (e.g. German umlauts)" puede coincidir con [a-z].

Si, por ejemplo,, Usted tiene la configuración regional alemana disponible, se puede comprobar de esta manera:

setlocale(LC_ALL, 'de_DE'); // German locale (not needed, but you never know...) 
echo preg_match('/^[a-z]+$/', 'abc') ? "yes\n" : "no\n"; 
echo preg_match('/^[a-z]+$/', "\xE4bc") ? "yes\n" : "no\n"; // äbc in ISO-8859-1 
echo preg_match('/^[a-z]+$/', "\xC3\xA4bc") ? "yes\n" : "no\n"; // äbc in UTF-8 
echo preg_match('/^[a-z]+$/u', "\xC3\xA4bc") ? "yes\n" : "no\n"; // w/ PCRE_UTF8 

de salida (no va a cambiar si se reemplaza de_DE con de_DE.UTF-8):

yes 
no 
no 
no 

La clase de caracteres [abcdefghijklmnopqrstuvwxyz] es idéntica a [a-z] en ambas codificaciones, el PCRE comprende: monobyte derivado de ASCII y UTF-8 (que también deriva de ASCII). En estas dos codificaciones, [a-z] es lo mismo que [\x61-\x7A].

Las cosas podrían haber sido diferentes cuando la pregunta fue hecha en 2009, pero en 2014 no hay "configuración extraña" que puede hacer que el motor de expresiones regulares PCRE de PHP interpretar [a-z] como una clase de más de 26 caracteres (siempre y cuando [a-z] propio está escrito como 5 bytes en una codificación derivada de ASCII, por supuesto).

+1

Lo ha clavado +1 – HamZa

+0

¿Qué sucede cuando se modifica el código del archivo PHP? –

+0

@AlanStorm: siempre que la codificación sea ISO-8859- *, UTF-8 o cualquier página de códigos de Windows que contenga el alfabeto en minúsculas en inglés: nada. Por otro lado, parece que PHP se puede compilar para leer, por ejemplo, el código fuente UTF-16 (no lo sabía). No tengo la energía para probarlo. Si alguien tiene, pueden publicar sus hallazgos aquí. –

7

Simplemente una adición a las respuestas ya excelentes, si es contradictorio.

La documentación para la biblioteca PCRE siempre ha declarado que "Los rangos operan en la secuencia de clasificación de los valores de los caracteres". Lo cual es algo vago, pero muy preciso.

Se refiere al cotejo por el índice de caracteres en las tablas de caracteres internos de PCRE, que se puede configurar para que coincida con la localización actual usando pcre_maketables. Esa función crea las tablas en orden de valor de char (tolower(i)/toupper(i))

En otras palabras, no se clasifica por orden de clasificación cultural real (la información de intercalación de locale). Como ejemplo, mientras que el alemán trata ö lo mismo que o en la recopilación del diccionario, ö tiene un valor que lo hace aparecer fuera del rango az en todas las codificaciones de caracteres comunes usadas para el alemán (ISO-8859-x, codificaciones unicode, etc.) En este caso, PCRE basaría su determinación de si ö está en el rango [a-z] en ese valor de código, en lugar de cualquier orden de clasificación definido en la configuración regional real.

PHP ha copiado en generalal es literal en their docs. Sin embargo, se han tomado la molestia de cambiar la declaración anterior a "Los rangos operan en secuencia de clasificación ASCII". Esa declaración ha estado en los documentos al menos desde 2004.

A pesar de lo anterior, no estoy muy seguro de que sea cierto, sin embargo.

Bueno, no en todos los casos, al menos.

El PHP hace una llamada a pcre_maketables ... Desde el PHP source:

#if HAVE_SETLOCALE 
    if (strcmp(locale, "C")) 
     tables = pcre_maketables(); 
#endif 

En otras palabras, si el entorno para el que se compila PHP tiene setlocale y la (LC_CTYPE) local no está se usa la configuración regional POSIX/C, el orden de caracteres de la configuración regional POSIX/C del entorno de ejecución. De lo contrario, se utilizan las tablas de PCRE por defecto - que son generados (por pcre_maketables) al compilar PCRE - basado en la configuración regional del compilador:

Esta función construye un conjunto de tablas de caracteres para los valores de carácter menos de 256. Estos pueden pasarse a pcre_compile() para anular las tablas integradas internas de PCRE (que fueron hechas por pcre_maketables() cuando se compiló PCRE).Es posible que desee hacer esto si está utilizando una configuración regional no estándar. La función produce un puntero a las tablas.

Mientras alemana no sería diferente para [a-z] en cualquier codificación de caracteres común, si se tratase de EBCDIC, por ejemplo, [a-z] incluiría ± e ~. De acuerdo, EBCDIC es la codificación de un carácter que puedo pensar que no coloca a-z y A-Z en una secuencia ininterrumpida.

A menos que PCRE haga algo de magia cuando use EBCDIC (y podría serlo), mientras que es muy poco probable que incluya diéresis en cualquier cosa que no sea la construcción PHP más oscura o el entorno de tiempo de ejecución (usando su propia, muy especial, personalizada definición de entorno local hecho), podría, en el caso de EBCDIC, incluir otros caracteres no deseados. Y para otros rangos, "intercalado en secuencia ASCII" no parece del todo exacto.

ETA: que podría haber salvado algunas investigaciones mediante la búsqueda de la respuesta del propio Philip Hazel a una preocupación similar:

Otro problema es con las clases de caracteres varía. Podrías pensar que [a-k] y [x-z] están bien definidos para los scripts latinos, pero ese no es el caso.

Son, ciertamente, bien definido, que es equivalente a [\ x61- \ X6B] y [\ x78- \ X7a], es decir, relacionados con el orden del código, no orden de clasificación cultural.

+1

[pcre_maketables()] (http://vcs.pcre.org/viewvc/code/trunk/pcre_maketables.c?view=markup) solo crea las siguientes tablas: tabla de mayúsculas inferior, tabla de volteo de mayúsculas y minúsculas, tablas de clase de caracteres, tabla de caracteres No se trata de intercalaciones. En cuanto a EBCDIC, si alguien me muestra una máquina EBCDIC que realmente ejecuta PHP, donde el PCRE dentro de PHP interpreta '[a-z]' como '[\ x81- \ xA9]', me rindo. –

+0

Sí. Por lo tanto, "en otras palabras, no se clasifica por orden de clasificación cultural real (la información de intercalación local)". El punto entero de la respuesta * es * que no se trata de intercalaciones. – JimmiTh

+1

La cosa de la perra con strcmp (3) es que devuelve el equivalente de falso, cuando las cadenas coinciden. Por lo tanto, pcre_maketables se llama para cualquier cosa, PERO la configuración regional C. – Melvyn

Cuestiones relacionadas