GNU/Linux >> Tutoriels Linux >  >> Linux

Différence entre [0-9], [[:digit:]] et D ?

Dans l'article de Wikipedia sur les expressions régulières, il semble que [[:digit:]] =[0-9] =d .

Quelles sont les circonstances où ils ne sont pas égaux? Quelle est la différence ?

Après quelques recherches, je pense qu'une différence est que l'expression entre parenthèses [:expr:] dépend des paramètres régionaux.

Réponse acceptée :

Oui, c'est [[:digit:]] ~ [0-9] ~ d (où ~ signifie approximatif).
Dans la plupart des langages de programmation (où il est pris en charge)

d ≡ `[[:digit:]]`            # (is identical to, it is a short hand for).  

Le d existe dans moins d'instances que [[:digit:]] (disponible dans grep -P mais pas en POSIX).

Chiffres Unicode

Il y a [de nombreux chiffres dans UNICODE](http://www.fileformat.info/info/unicode/category/Nd/list.htm), par exemple :

123456789 # Hindu-Arabic Chiffres arabes
٠١٢٣٤٥٦٧٨٩ # ARABIC-INDIC
۰۱۲۳۴۵۶۷۸۹ # EXTENDED ARABIC-INDIC/PERSIAN
߀߁߂߃߄߅߆߇߈߉ # NKO DIGIT
०१२३४५६७८९ # DEVANAGARI

Tout cela peut être inclus dans [[:digit:]] ou d , et même certains cas de [0-9] .

POSIX

Pour le BRE ou ERE POSIX spécifique :
Le d n'est pas pris en charge (pas dans POSIX mais dans GNU grep -P ). [[:digit:]] est requis par POSIX pour correspondre à la classe de caractères numériques, qui à son tour est requise par ISO C pour être les caractères 0 à 9 et rien d'autre. Donc uniquement dans les paramètres régionaux C tous [0-9] , [0123456789] , d et [[:digit:]] signifie exactement la même chose. Le [0123456789] n'a pas de mauvaises interprétations possibles, [[:digit:]] est disponible dans plus d'utilitaires et dans certains cas signifie uniquement [0123456789] . Le d est pris en charge par quelques utilitaires.

Comme pour [0-9] , la signification des expressions de plage n'est définie par POSIX que dans la locale C ; dans d'autres paramètres régionaux, il peut être différent (il peut s'agir de l'ordre des points de code, de l'ordre de classement ou de quelque chose d'autre).

[0123456789]

L'option la plus basique pour tous les chiffres ASCII.
Toujours valide, (AFAICT) aucune instance connue où elle échoue.

Il correspond uniquement aux chiffres anglais :0123456789 .

[0-9]

On pense généralement que [0-9] est uniquement les chiffres ASCII 0123456789 .
C'est terriblement faux dans certains cas :Linux dans certains paramètres régionaux qui ne sont pas des systèmes "C" (juin 2020), par exemple :

Supposons :

str='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'

Essayez grep pour découvrir qu'il permet à la plupart d'entre eux :

$ echo "$str" | grep -o '[0-9]+'
0123456789
٠١٢٣٤٥٦٧٨
۰۱۲۳۴۵۶۷۸
߀߁߂߃߄߅߆߇߈
०१२३४५६७८

Ce sed a quelques problèmes. Devrait supprimer uniquement 0123456789 mais supprime presque tous les chiffres. Cela signifie qu'il accepte la plupart des chiffres mais pas certains neuf (???):

$ echo "$str" | sed 's/[0-9]{1,}//g'
 ٩ ۹ ߉ ९

Cette même expr souffre des mêmes problèmes de sed :

expr "$str" : '([0-9 ]*)'             # also matching spaces.
0123456789 ٠١٢٣٤٥٦٧٨

Et aussi ed

printf '%sn' 's/[0-9]/x/g' '1,p' Q | ed -v <(echo "$str")
105
xxxxxxxxxx xxxxxxxxx٩ xxxxxxxxx۹ xxxxxxxxx߉ xxxxxxxxx९

[[:chiffre :]]

Il existe de nombreux langages :Perl, Java, Python, C. Dans lesquels [[:digit:]] (et d ) appelle un sens élargi. Par exemple, ce code perl correspondra à tous les chiffres ci-dessus :

$ str='0123456789 ٠١٢٣٤٥٦٧٨٩ ۰۱۲۳۴۵۶۷۸۹ ߀߁߂߃߄߅߆߇߈߉ ०१२३४५६७८९'

$ echo "$str" | perl -C -pe 's/[^d]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९

Ce qui équivaut à sélectionner tous les caractères qui ont les propriétés Unicode de Numeric et digits :

$ echo "$str" | perl -C -pe 's/[^p{Nd}]//g;' ; echo
0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९

Que grep pourrait reproduire (la version spécifique de pcre peut avoir une liste interne de points de code numérique différente de celle de Perl) :

$ echo "$str" | grep -oP 'p{Nd}+'
0123456789
٠١٢٣٤٥٦٧٨٩
۰۱۲۳۴۵۶۷۸۹
߀߁߂߃߄߅߆߇߈߉
०१२३४५६७८९

coquilles

Certaines implémentations peuvent comprendre qu'une plage est quelque chose de différent de l'ordre ASCII simple (ksh93 par exemple) (lorsqu'il est testé sur la version de mai 2018 (AT&T Research) 93u+ 2012-08-01) :

$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"
  ۹ ߀߁߂߃߄߅߆߇߈߉ ९

Maintenant (juin 2020), le même paquet ksh93 de debian (même version sh (AT&T Research) 93u+ 2012-08-01) :

$ LC_ALL=en_US.utf8 ksh -c 'echo "${1//[0-9]}"' sh "$str"

 ٩ ۹ ߉ ९

Et cela me semble être une source sûre de bugs en attente de se produire.

En relation:la différence entre les opérateurs Bash [[ vs [ vs ( vs ((?
Linux
  1. Différence entre le shell de connexion et le shell sans connexion ?

  2. Différence entre 2>&-, 2>/dev/null, |&, &>/dev/null et>/dev/null 2>&1 ?

  3. Quelle est la différence entre Sudo Su - et Sudo Su - ?

  4. Différence entre Eot et Eof?

  5. Différence entre les applications Gtk et Qt ?

Différence entre apt et apt-get expliquée

Différence entre Qemu et KVM

Différence entre $HOME et '~' (tilde) ?

différence entre netstat et ss sous linux?

Différence entre ${} et $() dans Bash

différence entre les cgroups et les espaces de noms