GNU/Linux >> Znalost Linux >  >> Linux

Rozdíl mezi [0-9], [[:digit:]] a D?

V článku o regulárních výrazech na Wikipedii se zdá, že [[:digit:]] =[0-9] =d .

Jaké jsou okolnosti, kdy se nerovnají? Jaký je rozdíl?

Po nějakém průzkumu si myslím, že jedním rozdílem je výraz v závorce [:expr:] závisí na národním prostředí.

Přijatá odpověď:

Ano, je to [[:digit:]] ~ [0-9] ~ d (kde ~ znamená přibližné).
Ve většině programovacích jazyků (kde je podporováno)

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

d existuje v menším počtu případů než [[:digit:]] (dostupné v grep -P ale ne v POSIX).

Číslice Unicode

V UNICODE je [mnoho číslic](http://www.fileformat.info/info/unicode/category/Nd/list.htm), například:

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

Všechny mohou být zahrnuty v [[:digit:]] nebo d a dokonce i některé případy [0-9] .

POSIX

Pro konkrétní POSIX BRE nebo ERE:
The d není podporován (není v POSIX, ale je v GNU grep -P ). [[:digit:]] je vyžadováno POSIX, aby odpovídalo třídě číslicových znaků, což zase vyžaduje ISO C, aby byly znaky 0 až 9 a nic jiného. Tedy pouze v národním prostředí C všechny [0-9] , [0123456789] , d a [[:digit:]] znamená úplně to samé. [0123456789] nemá žádné možné nesprávné interpretace, [[:digit:]] je k dispozici ve více nástrojích a v některých případech znamená pouze [0123456789] . d je podporováno několika nástroji.

Stejně jako [0-9] , význam výrazů rozsahu je definován pouze POSIX v národním prostředí C; v jiných lokalitách to může být jiné (může to být pořadí kódových bodů nebo řazení nebo něco jiného).

[0123456789]

Nejzákladnější možnost pro všechny číslice ASCII.
Vždy platné, (AFAICT) není znám případ, kdy by selhal.

Odpovídá pouze anglickým číslicím:0123456789 .

[0-9]

Obecně se má za to, že [0-9] jsou pouze číslice ASCII 0123456789 .
To je v některých případech bolestně nepravdivé:Linux v některých národních prostředích, které nejsou systémy „C“ (červen 2020), například:

Předpokládejme:

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

Zkuste grep zjistit, že většině z nich umožňuje:

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

Ten sed má nějaké problémy. Měli byste odstranit pouze 0123456789 ale odstraní téměř všechny číslice. To znamená, že přijímá většinu číslic, ale ne některé devítky (???):

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

Že dokonce expr trpí stejnými problémy jako sed:

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

A také ed

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

[[:digit:]]

Existuje mnoho jazyků:Perl, Java, Python, C. Ve kterém [[:digit:]] (a d ) vyžaduje rozšířený význam. Například tento kód perl bude odpovídat všem výše uvedeným číslicím:

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

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

Což je ekvivalentní výběru všech znaků, které mají vlastnosti Unicode Numeric a digits :

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

Který grep by mohl reprodukovat (konkrétní verze pcre může mít jiný vnitřní seznam číselných kódů než Perl):

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

mušle

Některé implementace mohou chápat rozsah jako něco jiného než obyčejná objednávka ASCII (například ksh93) (při testování ve verzi z května 2018 (AT&T Research) 93u+ 2012-08-01):

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

Nyní (červen 2020), stejný balíček ksh93 z debianu (stejná verze sh (AT&T Research) 93u+ 2012-08-01):

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

 ٩ ۹ ߉ ९

A to mi připadá jako jistý zdroj chyb, které čekají, až nastanou.

Související:rozdíl mezi operátory Bash [[ vs [ vs ( vs ((?
Linux
  1. Rozdíl mezi přihlašovacím prostředím a nepřihlašovacím prostředím?

  2. Rozdíl mezi 2>&-, 2>/dev/null, |&, &>/dev/null A>/dev/null 2>&1?

  3. Rozdíl mezi Gtk a Qt aplikacemi?

  1. Rozdíl mezi uživatelem Sudo a uživatelem root?

  2. Rozdíl mezi Snat a Masquerade?

  3. Rozdíl mezi Nss a Pam?

  1. Rozdíl mezi CLOCK_REALTIME a CLOCK_MONOTONIC?

  2. Rozdíl mezi GNUWin32 a cygwin

  3. Rozdíl mezi ${} a $() v Bash