LC_COLLATEは文字範囲に影響しますか?


27

照合順序LC_COLLATEは、個々の文字の並べ替え順序だけでなく、文字範囲の意味も定義します。それともそうですか?次のスニペットを検討してください。

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'

直感的にBはにない[a-z]ので、何も出力されません。それがUbuntu 8.04または10.04で起こります。しかし、Debianのレニーやスクイズを実行しているいくつかのマシン上で、B範囲があるため、発見されたa-zの間だすべてのものが含まaz大文字を含む照合順序で、BスルーをZ

テストされたすべてのシステムには、en_USロケールが生成されています。また、ロケールを変更しようとしました:B上記と一致するマシンでは、{en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}日本語(使用可能なエンコーディング)およびC/ を除くすべての使用可能なロケール(ほとんどがラテン語ベース:、中国語ロケールも)で同じことが起こりますPOSIX

ASCIIを超える場合、正規表現文字範囲は何を意味しますか?一部のDebianインストールと他のDebianインストールとUbuntuの間に違いがあるのはなぜですか?他のシステムはどのように動作しますか?誰が正しいのか、誰に対してバグを報告すべきか?

(主にGNU libcベースのシステム[a-z]でのen_USロケールなどの文字範囲の動作について具体的に尋ねていることに注意してください。小文字またはASCII小文字の一致方法は尋ねていません。)


2台のDebianマシンで、1台Bが入っ[a-z]ているものと入っていないものの出力LC_COLLATE=en_US locale -k LC_COLLATE

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"

そしての出力LC_COLLATE=en_US.utf8 locale -k LC_COLLATE

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"

1
便利なDebian Lennyインスタンスでは再現しません。en_USただし、が生成されたかどうかは確認しませんでした。
アレックス

1
@alexロケールが生成されない場合、そのロケールはCフォールバックとして使用され、その照合順序はストレートバイト値であるため、B一致しません。の出力に表示されるロケールでテストしますlocale -a
ジル 'SO-悪である停止

1
en_USはen_US.utf8と同じではなく、インストールした内容に応じて、通常はen_US.iso-8859-1を意味することに注意してください。ロケール-aの出力にen_US(接尾辞なし)が表示されない場合、実際にはこのロケールはありません。LC_COLLATE = en_US locale -k LC_COLLATEは何を表示しますか?
ニールメイヒュー

1
これはその後、ここでは理論的な質問ではなく実用的な質問になりました:なぜawk正規表現の小文字の範囲に大文字が含まれているのですか?
カレブ

1
@isaac残念ながら、7年後、私は問題のあるシステムにアクセスできないようです。それらはすべてアップグレードまたは廃止されました。
ジル 'SO-悪であるのをやめる'

回答:


3

Cロケール以外を使用している場合[a-z]、これらはロケール依存であり、期待する結果が常に得られるとは限らないため、範囲を使用しないでください。既に遭遇したケースの問題に加えて、いくつかのロケールは発音区別記号(例:á)を持つ文字を基本文字と同じように扱います(すなわち a)ます。

代わりに、名前付き文字クラスを使用します。

echo B | grep '[[:lower:]]'

これにより、ロケールの正しい結果が常に得られます。ただし、入力テキストと適用しようとしているテストの両方の意味を反映するロケールを選択する必要があります。

たとえば、特定のバイト値を見つける必要がある場合Cは、常に使用可能なロケールを使用します。

echo B | LANG=C grep '[a-z]'

これが期待どおりに機能しない場合、それは本当にバグです。


私はそれを知っている、それは私が尋ねたものではありません。明示的な範囲が何を意味するのか、そして異なるディストリビューション(GNU libcとGNU grepを含む)が異なる動作をする理由について具体的に尋ねています。(あなたの言うことは正しいのに、それは無関係だからです。)
ジル「SO-悪であるのをやめ

1
私のポイントは、明示的な範囲の意味はロケールに依存し、異なるシステムが同じ方法でロケールを定義する必要がないため、これはバグではないということです。技術的には、システムを悪用しているため、「未定義」の動作に驚かないでください。また、Debianシステムで動作を再現できないとコメントしている人もいるので、あなたのシステムには何か異常があるようです。
ニールメイヒュー

1
範囲の動作はロケールに依存することを知っています。私は、Glibcを使用するシステム(および同じDebianリリースのインストールが異なる場合でも)が異なる動作をすることを驚かせています。の出力をlocale -k質問に追加しました。2台のDebianマシンで同じですが、1台Bは範囲内にあり、もう1台はそうではありません。ところで、私はどちらのマシンでもrootではありません(したがって、管理者として行うのは特別なことではありません)。
ジル 'SO-悪であるのをやめる'

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'リターンaüしばらくの間echo "Baü" | LC_COLLATE=C grep -o '[a-z]'だけ戻りますa。私の目には、「下げる」OPが望んで実際にはない
ダニエル・アルダー

ただし、私の元のポイントはまだ立っていCます。ロケールを使用しない限り、範囲を使用しないでください。これは、バグを報告しようとしていたOPに関係があると思います。Cロケールを使用していない場合、範囲を使用した結果は非常に予測不能であるため、バグと見なすことはできません。一方、特定のバイト値を見つける必要がある場合は、Cロケールを使用します。私の第二のポイントは、ロケールで実際に小文字を検索したい場合は、文字クラスを使用することです。OPはこれを探していなかったかもしれませんが、この質問を見つけた場合は他の人が見つけるかもしれません。
ニールメイヒュー

1

正規表現の範囲は、照合設定に従う必要があります。関連する標準は次のとおりです。http//pubs.opengroup.org/onlinepubs/007908799/xbd/re.html(「範囲式」を探してください)。そのため、それぞれのロケールの適切な定義を指定してecho B | LC_COLLATE=en_US grep '[a-z]'出力Bする必要があります。なぜこれがうまく機能しないのかを説明することはできませんが、適切にインストールおよび設定された非古代のシステムでこれに遭遇した場合、非常に驚​​くでしょう。


1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' Ubuntu 12.04でgrep 2.10を使用しても何も印刷されません。CentOS 6.5でgrep 2.6.3を使用して何も印刷しません。Debian 6.0.8とgrep 2.6.3で動作します。
イアンD.アレン14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.