2009-05-20 20 views
36

Después de leer una serie de preguntas/respuestas más de las últimas semanas, he visto el uso de \d en las expresiones regulares de Perl comentadas como incorrecta. Como en las versiones posteriores de perl \d no es lo mismo que [0-9], como \d representará cualquier carácter Unicode que tenga el atributo de dígito, y que [0-9] representa los caracteres '0', '1', '2', ..., '9'.¿Debo usar d o [0-9] para unir los dígitos en una expresión regular de Perl?

Aprecio que en algunos contextos [0-9] será lo correcto para usar, y en otros \d será. Me preguntaba qué personas creen que es el valor predeterminado correcto para usar.

Personalmente encuentro la notación \d muy sucinta y expresiva, mientras que en comparación [0-9] es algo engorroso. Pero tengo poca experiencia en hacer código en varios idiomas, o más bien código para idiomas que no encajan en el rango de caracteres ASCII, y por lo tanto, puede estar siendo ingenuo.

noto

$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\\d' | wc -l 
    298 
$find /System/Library/Perl/5.8.8/ -name \*pm | xargs grep '\[0-9\]' | wc -l 
    26 

Respuesta

28

Para mayor seguridad, me gustaría sugerir el uso de [0-9] cualquier momento usted no tiene intención específicamente para que coincida con todos los dígitos Unicode definidos.

por perldoc perluniintro, Perl no es compatible con el uso de dígitos que no sean [0-9] como números, por lo que definitivamente me gustaría utilizar [0-9] si los siguientes son ambas verdaderas:

  1. que desea utilizar el resultado como un número (como realizar operaciones matemáticas en él o almacenarlo en algún lugar que solo acepte números apropiados (por ejemplo, una columna INT en una base de datos)).

  2. Es posible que los dígitos no [^0-9] estén presentes en los datos de tal manera que la expresión regular podría coincidir con ellos. (Tenga en cuenta que éste debe siempre ser considerado válido para la entrada no es de confianza/hostil.)

Si cualquiera de estos son falsos, habrá sólo en raras ocasiones haber una razón para específicamente no uso \d (y' ll probablemente será capaz de decir cuando ese es el caso), y si estás tratando para que coincida con todos los dígitos definidos por Unicode, que sin duda desea utilizar \d.

+2

\ d puede coincidir con más de 10 caracteres diferentes, si se aplica a cadenas Unicode. – pts

3

me siento ambos deben tener su lugar. Sin embargo, el 99,999% de las veces (especialmente en mi gran mundo cerrado de cooperación estadounidense) son intercambiables. Uso perl para manipular datos todos los días y en ninguno de los conjuntos de datos con los que trato hay números que no encajan en [0-9]. Sin embargo, aprecio que hay una distinción importante entre \d y [0-9] y es bueno ser consciente de esa diferencia. Uso \d porque parece más sucinto (como dijiste) y nunca estaría "mal" en mi pequeño mundo de manipulación de datos.

+0

Usted quiere \ d not/d - si lo desea en absoluto. – Telemachus

2

Si aplica \d a una cadena Unicode (como en "\X{660}" =~ /\d/), coincidirá con un dígito Unicode. Si se aplica \d a una cadena binaria (como el UTF-8 equivalente de lo anterior: "\xd9\xa0" =~ /\d/), que coincidirá con sólo los 10 dígitos ASCII. Perl 5.8 no crea cadenas Unicode por defecto (a menos que lo solicite específicamente, como en "\X{...}" o use utf8; etc.).

Así que mi consejo es: solo preste atención a la diferencia entre \d y [0-9] si su aplicación utiliza cadenas Unicode.

8

Según perlreref, '\d' es compatible con la configuración regional y es compatible con Unicode.

Sin embargo, si el conjunto de códigos que está utilizando no es Unicode, entonces no necesita preocuparse por los dígitos Unicode, y si el conjunto de códigos que está utilizando es algo así como Latin-1 (ISO 8859-1, o 8859 -15), entonces el conocimiento de la configuración regional no le hará daño tampoco porque el conjunto de códigos no incluye ningún otro dígito.

Por lo tanto, para muchas personas, la mayoría de las veces, puede utilizar '\d' sin preocupaciones. Sin embargo, si los datos de Unicode son parte de tu trabajo, entonces debes considerar lo que buscas con más cuidado.

4

Al igual que aniquilar el sitio desde la órbita, [0-9] es la única manera de estar seguro. Sí, es feo. Sí, la elección de hacer que \d sea UNICODE y consciente de la configuración regional era estúpido. Pero esta es nuestra cama y tenemos que mentir en ella.

En cuanto a las personas agachando la cabeza en la arena diciendo que no afecta el conjunto de caracteres que están usando hoy, bien puede estar usando ese conjunto de caracteres hoy, pero el resto del mundo está usando UTF-8 ahora y lo usarás pronto también. Recuerde codificar como si el tipo que mantiene su código es un maníaco homicida que sabe dónde vive.

Ah, y en cuanto a los módulos Perl que usan \d frente a , incluso el núcleo todavía tiene UNICODE problems.

Si lo hace, de hecho, cualquier dígito, pero quiere ser capaz de hacer operaciones matemáticas con los resultados, puede utilizar Text::Unidecode:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Text::Unidecode; 

my $number = "\x{1811}\x{1812}\x{1813}\x{1814}\x{1815}"; 
print "$number is ", unidecode($number), "\n"; 

Después de algunas pruebas más se ve como texto :: Unidecode doesn' Manejar todos los caracteres de dígitos correctamente. Estoy escribiendo un module que funcionará.

44

Me parece muy peligroso usar \d, es una mala decisión de diseño en el idioma, como en la mayoría de los casos desea [0-9]. La codificación de Huffman dictaría el uso de \d para los números ASCII.

La mayoría de los críticos anteriores ya se han puesto de relieve por las que debe utilizar [0-9], por lo que te voy a dar un poco más de datos:

  • Si leo las tablas Unicode correctamente '۷۰' es un número (70 en indic, no tome mi palabra para eso).

  • Prueba esto:

    $ perl -le '$one = chr 0xFF11; print "$one + 1 = ", $one+1;' 
    1 + 1 = 1 
    
  • Aquí está una lista parcial de los números válidos (que pueden o no aparecer correctamente en su navegador, en función de los tipos que utiliza), para cada número, sólo se el primero de los que están siendo interpretados como un número al hacer aritmética con Perl, como se muestra arriba:

    ZERO: 0٠۰߀०০੦૦୦௦౦೦൦๐໐0 
    ONE: 1١۱߁१১੧૧୧௧౧೧൧๑໑1 
    TWO: 2٢۲߂२২੨૨୨௨౨೨൨๒໒2 
    THREE: 3٣۳߃३৩੩૩୩௩౩೩൩๓໓3 
    FOUR: 4٤۴߄४৪੪૪୪௪౪೪൪๔໔4 
    FIVE: 5٥۵߅५৫੫૫୫௫౫೫൫๕໕5 
    SIX: 6٦۶߆६৬੬૬୬௬౬೬൬๖໖6 
    SEVEN: 7٧۷߇७৭੭૭୭௭౭೭൭๗໗7 
    EIGHT: 8٨۸߈८৮੮૮୮௮౮೮൮๘໘8 
    NINE: 9٩۹߉९৯੯૯୯௯౯೯൯๙໙9�� 
    

¿aún no está convencido?

+4

+1 para esa lista! Estaba empezando a preguntarme qué otros personajes numéricos había. – nickf

+1

Si Perl ha adoptado UNICODE hasta ahora, parece que debería seguir el resto del camino y manejar todos los dígitos. Por supuesto, de esa manera se encuentra la locura, pero ¿no es la locura el destino de todos los programadores de Perl ;-)? – RBerteig

+0

todavía hay más caracteres, pero solo incluí los que podía mostrar en mi sistema. Utilicé los datos Unicode de http://www.unicode.org/Public/UNIDATA/UnicodeData.txt y extraje la información del personaje de allí. – mirod

1

Si [0-9] se siente torpe, quizás podría definir: $d=qr/[0-9]/; y usar eso en lugar de \d.

0

Como controles de formato de datos aumentan, la necesidad de patrón de especificidad baja ...

ejemplo, si usted está emparejando un fragmento de información que se ha generado la máquina y siempre sigue las mismas reglas de formato de salida, no necesita ser tan preciso Tome direcciones IPv4. Si usted está tratando de extraer la dirección IP de una línea de configuración de la interfaz del router, todo lo que realmente necesita es algo así como:

'ip\haddress\h(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\D' 

Si, por el contrario, usted está tratando de encontrar una dirección IP incrustado profundamente en algún lugar de , digamos, un X-Header por correo electrónico, o si está tratando de VALIDAR una dirección IP, bueno ... ¡eso es toda una historia!

Cuestiones relacionadas