GNU/Linux >> Tutoriales Linux >  >> Linux

¿Diferencia entre [0-9], [[:digit:]] y D?

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 ((?
Linux
  1. ¿La diferencia entre [[ $a ==Z* ]] y [ $a ==Z* ]?

  2. ¿Diferencia entre 2>&-, 2>/dev/null, |&, &>/dev/null y>/dev/null 2>&1?

  3. ¿Diferencia entre tubería y expansión de comando?

  4. ¿La diferencia entre Nss y Pam?

  5. Diferencia entre Qemu y KVM

Explicación de la diferencia entre apt y apt-get

¿Diferencia entre Snat y Masquerade?

¿Diferencia entre CLOCK_REALTIME y CLOCK_MONOTONIC?

diferencia entre netstat y ss en linux?

Diferencia entre ${} y $() en Bash

diferencia entre cgroups y espacios de nombres