[0-9]、[[:digit:]]と\ dの違い


35

正規表現上のWikipediaの記事、それがいるようです[[:digit:]]= [0-9]= \d

それらが等しくない状況は何ですか?違いはなんですか?

いくつかの調査の後、1つの違いはブラケット式[:expr:]がロケールに依存していることだと思います。


3
あなたが質問答えるためにリンクしたウィキペディアの記事ではありませんか?さまざまな正規表現プロセッサ/エンジンは、(特に)文字クラスのさまざまな構文をサポートしています。
イガル

@igal wikiは違いはあると言っていますが、詳細は述べていません。スリッグは、アイザックのような詳細を尋ねています。GNUバージョンかどうかに関係なく、grep、sed、awkの違いにかなり興味があります。
ハルビン

回答:


40

はい、そうです[[:digit:]][0-9]\d(どこ〜手段aproximate)。
ほとんどのプログラミング言語(サポートされている場合)\d[[:digit:]](同一)。未満が一般的です(POSIXにはないが、それはGNUです)。
\d[[:digit:]]grep -P

UNICODEに多くの数字があります。例:

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

これのすべてが含まれることができる[[:digit:]]\d

代わりに、[0-9]通常はASCII数字のみ0123456789です。


多くの言語があります:Perl、Java、Python、C。ここで[[:digit:]](および\d)拡張された意味を要求します。たとえば、このperlコードは上記のすべての数字と一致します。

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

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

これは、NumericおよびのUnicodeプロパティを持つすべての文字を選択することと同等digitsです。

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

どのgrepが再現できるか(pcreの特定のバージョンには、Perlとは異なる数値コードポイントの内部リストがある場合があります):

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

表示するには[0-9]に変更します。

$ echo "$a" | grep -o '[0-9]\+'
0123456789

POSIX

特定POSIX BREまたはEREの場合:(ないPOSIXではなく、GNUにあるサポートされていません)。 POSIXでは数字文字クラスに対応する必要があり、数字CはISO Cで文字0〜9以外の文字ではないことが必要です。だから、唯一のCにロケールすべてを、、とまったく同じ意味。何の可能性誤解を持っていない、より多くのユーティリティで利用可能で、それだけで意味するのが一般的です。いくつかのユーティリティでサポートされています。
\dgrep -P[[:digit:]][0-9][0123456789]\d[[:digit:]][0123456789][[:digit:]][0123456789]\d

に関しては[0-9]、範囲式の意味はCロケールのPOSIXによってのみ定義されます。他のロケールでは異なる場合があります(コードポイント順、照合順、またはその他の可能性があります)。

貝殻

実装によっては、範囲をプレーンASCII順序(ksh93など)とは異なるものとして理解する場合があります。

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

そして、それが起こるのを待っているバグの確かな源です。


実際には、POSIXシステム、iswctype()およびPOSIXユーティリティのBRE / ERE /ワイルドカードでは、[0-9]と[[:digit:]]は0123456789でのみ一致します。そして、それは標準の次のリビジョンで明示的に行われます
ステファンChazelas

私がいることを知らなかったperl\dUnicodeモードでは、他のスクリプトからの小数点以下の桁に一致します。ありがとう。PCREでは(*UCP)、GNUのように、grep -Po '(*UCP)\d'またはgrep -Po '(*UCP)[[:digit:]]Unicodeプロパティに基づいたクラスを参照してください。
ステファンシャゼラス

[:digit:]ローカライズ、つまりユーザーが数字と見なすものを使用することを構文が示唆していることに同意します。私は決して使用しない[:digit:]のと同じです、実際にので、[0-9]必ず、私は0123456789に一致させたい、どのような場合とでは、私が一致することを意味したことがない٠١٢٣٤٥٦٧٨٩、と私は1つは、小数点の桁に一致したいユースケースを考えることはできませんPOSIXユーティリティを使用したスクリプトで。zsh MLに関する現在の議論[:blank:]も参照してください。これらの文字クラスは少し複雑です。
ステファンシャゼル

13

これは、数字の定義方法によって異なります。[0-9]ASCIIのみになる傾向があります(または、ASCIIでもASCIIのスーパーセットでもないが、異なるビット表現(EBCDIC)のみのASCIIの場合と同じ10桁)。\d一方、いずれかの単なる数字(のPerlの古いバージョン、またはでのPerlの最近のバージョン可能性があり/a、正規表現フラグ有効)またはそれはのUnicodeの試合になる可能性\p{Digit}はなく、数字の大きなセットである[0-9]/\d/aのマッチ。

$ 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 詳細については、問題の言語のドキュメントを参照して、その動作を確認してください。

しかし、待ってください、まだあります!ロケールは\d一致するものによって異なる場合があるため、一致\dするUnicodeの完全なセットよりも少ない数字に一致する可能性があり、(できれば、通常)も含まれ[0-9]ます。これは、Cのisdigit(3)[0-9])とisnumber(3)[0-9プラスロケールからのその他)の違いに似ています。

数字の値を取得するために呼び出しが行われる場合があり[0-9]ます。

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

isnumber()少なくともそうだと思われるマニュアルページに基づいて、BSDのことだと思う
-ilkkachu

私ははい、BSDバイアスの何かを持っている
thrig

/ aフラグは、Unicodeの数字のリストのみを照合するように制限する特定のリミッターです。/a修飾子を使用すると、\ dをASCII 0〜9のみに一致させることができます。そのため、まったく同じのみを強制的に一致させ[0-9]ます。
アイザック

5

およびの異なる意味は[0-9]、他の回答に示されています。ここで、正規表現エンジンの実装に違いを追加したいと思います。[[:digit:]]\d

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

したがって、[[:digit:]]常に動作します\d依存します。grepのマニュアルでは、ロケールにある[[:digit:]]と述べられて0-9Cます。

PS1:詳細をご存知の場合は、表を展開してください。

PS2:テストにはGNU grep 3.1およびGNU 4.4が使用されます。


2
1)とには多くのバージョンがgrepありsed、おそらくGNUバージョンと他のバージョンとの間に最大の違いがあります。この回答は、どのバージョンでgrepあり、どのバージョンをsed参照しているのかを説明していると、より役立つ場合があります。または、そのテーブルのソースが何であるかということです。2)そのテーブルは画像である必要があるものが含まれていないため、テキストに転写される可能性があります
-ilkkachu

@ilkkachu 1)最新のGNU grep 3.1およびGNU 4.4がテストに使用されます。2)テーブルを作成する方法がありません。@ muruがテーブルをきれいなテキスト形式に変換したようです。
ハルビン

@harbinn回答にそれを編集してください。
ダンD.

@DanD。追加されたバージョン情報。注意のための
thx-ハルビン

1
pythonビルトインreモジュールは[[:digit:]]をサポートしていませんが、アドインライブラリregexはそれをサポートしているので、常に少し動作するようにします。POSIXの苦情の状況では常に機能します。
スティーブバーンズ

4

理論的な違いは他の回答ですでに十分に説明されているので、実際の違いを説明するために残っています。

以下は、数字を照合するためのより一般的な使用例です。


ワンショットデータ抽出

多くの場合、いくつかの数字を圧縮したい場合、数字自体は扱いにくい形式のテキストファイルにあります。プログラムで使用するためにそれらを抽出します。おそらく、(ファイルを見て)数値形式と現在のロケールを伝えることができるので、ジョブが完了する限り、どのフォームを使用しても構いません\d必要なキーストロークが最も少ないため、非常に一般的に使用されています。

入力サニタイズ

信頼されていないユーザー入力(Webフォームからの入力など)があり、予期しない内容が含まれていないことを確認する必要があります。データベースの数値フィールドに保存したり、シェルコマンドのパラメーターとして使用してサーバーで実行したい場合があります。この場合、[0-9]最も制限的で予測可能なものなので、本当に必要です。

データ検証

「危険」なものには使用しないデータが少しありますが、それが数値であるかどうかを知っておくと便利です。たとえば、プログラムでユーザーが住所を入力できるようにし、入力に家番号が含まれていない場合は、入力ミスを強調したい場合があります。この場合、あなたはおそらくできるだけ広くしたいので[[:digit:]]、行く方法です。


これらは、数字照合の3つの最も一般的な使用例のようです。重要なものを見逃したと思われる場合は、コメントをお寄せください。


良い仕事です。ReDoSなどのセキュリティ問題に関連していますか
フラム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.