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 ((?