En el artículo de Wikipedia sobre expresiones regulares, parece que [[:digit:]]
=[0-9]
=d
.
¿Cuáles son las circunstancias en las que no son iguales? ¿Cuál es la diferencia?
Después de investigar un poco, creo que una diferencia es que la expresión entre corchetes [:expr:]
depende de la configuración regional.
Respuesta aceptada:
Sí, es [[:digit:]]
~ [0-9]
~ d
(donde ~ significa aproximado).
En la mayoría de los lenguajes de programación (donde se admite)
d ≡ `[[:digit:]]` # (is identical to, it is a short hand for).
El d
existe en menos instancias que [[:digit:]]
(disponible en grep -P
pero no en POSIX).
Dígitos Unicode
Hay [muchos dígitos en UNICODE](http://www.fileformat.info/info/unicode/category/Nd/list.htm), por ejemplo:
123456789 # Hindu-Arabic
Números arábigos٠١٢٣٤٥٦٧٨٩ # ARABIC-INDIC
۰۱۲۳۴۵۶۷۸۹ # EXTENDED ARABIC-INDIC/PERSIAN
߀߁߂߃߄߅߆߇߈߉ # NKO DIGIT
०१२३४५६७८९ # DEVANAGARI
Todo lo cual puede incluirse en [[:digit:]]
o d
, e incluso algunos casos de [0-9]
.
POSIX
Para el POSIX BRE o ERE específico:
El d
no es compatible (no en POSIX pero sí en GNU grep -P
). [[:digit:]]
POSIX requiere que corresponda a la clase de carácter de dígito, que a su vez ISO C requiere que sean los caracteres del 0 al 9 y nada más. Así que solo en la configuración regional C todos [0-9]
, [0123456789]
, d
y [[:digit:]]
significa exactamente lo mismo. El [0123456789]
no tiene posibles interpretaciones erróneas, [[:digit:]]
está disponible en más utilidades y en algunos casos significa solo [0123456789]
. El d
es compatible con algunas utilidades.
En cuanto a [0-9]
, el significado de las expresiones de rango solo lo define POSIX en la configuración regional C; en otras configuraciones regionales podría ser diferente (podría ser el orden de los puntos de código o el orden de intercalación o algo más).
[0123456789]
La opción más básica para todos los dígitos ASCII.
Siempre válido, (AFAICT) sin instancia conocida donde falle.
Solo coincide con dígitos en inglés:0123456789
.
[0-9]
Generalmente se cree que [0-9]
son solo los dígitos ASCII 0123456789
.
Eso es dolorosamente falso en algunos casos:Linux en alguna configuración regional que no es sistemas "C" (junio de 2020), por ejemplo:
Supongamos:
str='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'
Prueba grep
para descubrir que permite a la mayoría de ellos:
$ echo "$str" | grep -o '[0-9]+'
0123456789
٠١٢٣٤٥٦٧٨
۰۱۲۳۴۵۶۷۸
߀߁߂߃߄߅߆߇߈
०१२३४५६७८
Ese sed tiene algunos problemas. Debe eliminar solo 0123456789
pero elimina casi todos los dígitos. Eso significa que acepta la mayoría de los dígitos pero no algunos nueve (???):
$ echo "$str" | sed 's/[0-9]{1,}//g'
٩ ۹ ߉ ९
Que incluso expr sufre de los mismos problemas de sed:
expr "$str" : '([0-9 ]*)' # also matching spaces.
0123456789 ٠١٢٣٤٥٦٧٨
Y también ed
printf '%sn' 's/[0-9]/x/g' '1,p' Q | ed -v <(echo "$str")
105
xxxxxxxxxx xxxxxxxxx٩ xxxxxxxxx۹ xxxxxxxxx߉ xxxxxxxxx९
[[:dígito:]]
Hay muchos lenguajes:Perl, Java, Python, C. En los que [[:digit:]]
(y d
) exige un significado ampliado. Por ejemplo, este código perl coincidirá con todos los dígitos de arriba:
$ str='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'
$ echo "$str" | perl -C -pe 's/[^d]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९
Lo que equivale a seleccionar todos los caracteres que tienen las propiedades Unicode de Numeric
y digits
:
$ echo "$str" | perl -C -pe 's/[^p{Nd}]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९
Qué grep podría reproducir (la versión específica de pcre puede tener una lista interna diferente de puntos de código numérico que Perl):
$ echo "$str" | grep -oP 'p{Nd}+'
0123456789
٠١٢٣٤٥٦٧٨٩
۰۱۲۳۴۵۶۷۸۹
߀߁߂߃߄߅߆߇߈߉
०१२३४५६७८९
conchas
Algunas implementaciones pueden entender que un rango es algo diferente al orden ASCII simple (ksh93, por ejemplo) (cuando se probó en la versión de mayo de 2018 (AT&T Research) 93u+ 2012-08-01):
$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"
۹ ߀߁߂߃߄߅߆߇߈߉ ९
Ahora (junio de 2020), el mismo paquete ksh93 de debian (misma versión sh (AT&T Research) 93u+ 2012-08-01):
$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"
٩ ۹ ߉ ९
Y eso me parece una fuente segura de errores esperando a suceder.
Relacionado:la diferencia entre los operadores de Bash [[ vs [ vs ( vs ((?