it-swarm.com.de

Unterschied zwischen [0-9], [[: Ziffer:]] und \ d

In dem Wikipedia-Artikel über reguläre Ausdrücke scheint [[:digit:]] = [0-9] = \d.

Unter welchen Umständen sind sie nicht gleich? Was ist der Unterschied?

Nach einigen Recherchen denke ich, dass ein Unterschied darin besteht, dass der Klammerausdruck [:expr:] ist vom Gebietsschema abhängig.

37
harbinn

Ja, es ist [[:digit:]] ~ [0-9] ~ \d (Wobei ~ ungefähr bedeutet).
In den meisten Programmiersprachen (wo es unterstützt wird) \d[[:digit:]] (Identisch).
Der \d Ist weniger verbreitet als [[:digit:]] (Nicht in POSIX, aber in GNU grep -P).

Es gibt viele Ziffern in UNICODE , zum Beispiel:

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

All dies kann enthalten sein in [[:digit:]] Oder \d.

Stattdessen besteht [0-9] Im Allgemeinen nur aus den Ziffern ASCII] 0123456789.


Es gibt viele Sprachen: Perl, Java, Python, C. In denen [[:digit:]] (Und \d) Eine erweiterte Bedeutung erfordern. Dieser Perl-Code stimmt beispielsweise mit allen Ziffern von oben überein:

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

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

Dies entspricht der Auswahl aller Zeichen mit den Unicode-Eigenschaften Numeric und digits:

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

Welcher Grep könnte reproduziert werden (die spezifische Version von pcre enthält möglicherweise eine andere interne Liste numerischer Codepunkte als Perl):

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

Ändern Sie es in [0-9], um Folgendes anzuzeigen:

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

POSIX

Für das spezifische POSIX BRE oder ERE:
Der \d Wird nicht unterstützt (nicht in POSIX, sondern in GNU grep -P). [[:digit:]] Wird von POSIX benötigt um der Ziffernzeichenklasse zu entsprechen, die wiederum von ISO C als Zeichen 0 bis 9 und sonst nichts benötigt wird. Also nur im Gebietsschema C Alle [0-9], [0123456789], \d und [[:digit:]] bedeuten genau dasselbe. Der [0123456789] hat keine möglichen Fehlinterpretationen, [[:digit:]] ist in mehr Dienstprogrammen verfügbar und bedeutet üblicherweise nur [0123456789]. Das \d wird von wenigen Dienstprogrammen unterstützt.

Bei [0-9] Wird die Bedeutung von Bereichsausdrücken nur von POSIX im Gebietsschema C definiert. In anderen Regionen kann dies anders sein (Codecode-Reihenfolge oder Sortierreihenfolge oder etwas anderes).

muscheln

Einige Implementierungen verstehen einen Bereich möglicherweise als etwas anderes als normal ASCII order (zsh93 zum Beispiel):

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

Und das ist eine sichere Quelle für Fehler, die darauf warten, passiert zu werden.

42
Isaac

Dies hängt davon ab, wie Sie eine Ziffer definieren. [0-9] Sind in der Regel nur die ASCII) (oder möglicherweise etwas anderes, das weder ASCII noch eine Obermenge von ASCII aber die gleichen 10 Ziffern wie in ASCII nur mit unterschiedlichen Bitdarstellungen (EBCDIC)); \d könnten andererseits entweder nur die einfachen Ziffern sein (alt Versionen von Perl oder moderne Versionen von Perl mit aktiviertem Flag für reguläre Ausdrücke /a) oder es könnte sich um eine Unicode-Übereinstimmung von \p{Digit} handeln, die eher aus Ziffern besteht als [0-9] oder /\d/a stimmen überein.

$ Perl -E 'say "match" if 42 =~ m/\d/'
match
$ Perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/'
match
$ Perl -E 'say "match" if "\N{U+09EA}" =~ m/\d/a'
$ Perl -E 'say "match" if "\N{U+09EA}" =~ m/[0-9]/'
$ 

perldoc perlrecharclass Weitere Informationen erhalten Sie in der Dokumentation der betreffenden Sprache, um zu erfahren, wie sie sich verhält.

Aber warte, da ist noch mehr! Das Gebietsschema kann auch variieren, was \d Entspricht, sodass \d Weniger Ziffern als der gesamte Unicode-Satz entsprechen kann und (hoffentlich normalerweise) auch [0-9] Enthält. Dies ähnelt dem Unterschied in C zwischen isdigit(3) ([0-9]) Und isnumber(3) ([0-9 Plus was auch immer aus dem Gebietsschema).

Es können Anrufe getätigt werden, um den Wert der Ziffer zu erhalten, auch wenn dies nicht [0-9] Ist:

$ Perl -MUnicode::UCD=num -E 'say num(4)'
4
$ Perl -MUnicode::UCD=num -E 'say num("\N{U+09EA}")'
4
$ 
14
thrig

Unterschiedliche Bedeutung von [0-9], [[:digit:]] und \d werden in anderen Antworten dargestellt. Hier möchte ich Unterschiede in der Implementierung der Regex-Engine hinzufügen.

            [[:digit:]]    \d
grep -E               ✓     ×
grep -P               ✓     ✓
sed                   ✓     ×
sed -E                ✓     ×

Damit [[:digit:]] funktioniert immer, \d hängt davon ab. In greps Handbuch wird erwähnt, dass [[:digit:]] ist nur 0-9 im Gebietsschema C.

PS1: Wenn Sie mehr wissen, erweitern Sie bitte die Tabelle.

PS2: GNU grep 3.1 und GNU 4.4 wird zum Testen verwendet.

7
harbinn

Die theoretischen Unterschiede wurden bereits in den anderen Antworten ziemlich gut erklärt, daher müssen noch die praktischen Unterschiede erklärt werden.

Hier sind einige der häufigsten Anwendungsfälle für das Abgleichen einer Ziffer:


One-Shot-Datenextraktion

Wenn Sie einige Zahlen knacken möchten, befinden sich die Zahlen häufig in einer umständlich formatierten Textdatei. Sie möchten sie zur Verwendung in Ihrem Programm extrahieren. Sie können wahrscheinlich das Zahlenformat (anhand der Datei) und Ihr aktuelles Gebietsschema angeben. Es ist also in Ordnung, eines der Formulare zu verwenden, solange die Aufgabe erledigt ist. \d erfordert die wenigsten Tastenanschläge, daher wird es sehr häufig verwendet.

Desinfektion der Eingabe

Sie haben einige nicht vertrauenswürdige Benutzereingaben (möglicherweise aus einem Webformular) und müssen sicherstellen, dass diese keine Überraschungen enthalten. Vielleicht möchten Sie es in einem numerischen Feld in einer Datenbank speichern oder als Parameter für einen Shell-Befehl verwenden, der auf einem Server ausgeführt wird. In diesem Fall möchten Sie wirklich [0-9], da es das restriktivste und vorhersehbarste ist.

Datenvalidierung

Sie haben ein paar Daten, die Sie nicht für "gefährliche" Zwecke verwenden werden, aber es wäre schön zu wissen, ob es sich um eine Zahl handelt. In Ihrem Programm kann der Benutzer beispielsweise eine Adresse eingeben, und Sie möchten einen möglichen Tippfehler hervorheben, wenn die Eingabe keine Hausnummer enthält. In diesem Fall möchten Sie wahrscheinlich so breit wie möglich sein, also [[:digit:]] ist der richtige Weg.


Dies scheinen die drei häufigsten Anwendungsfälle für den Ziffernabgleich zu sein. Wenn du denkst, ich habe einen wichtigen verpasst, schreibe bitte einen Kommentar.

5
Bass