19

これは本当に二重の質問です。私の2つの最終目標には、次の答えがあります。

  • メカニズムの観点から、標準の文字列比較順序は何ですか?
  • ドキュメントを更新できるようにするためのより良い名前は何ですか?

ソートに関するPerlのドキュメントには、ブロックなしでsort「標準の文字列比較順序」を使用すると記載されています。しかし、その順序は何ですか?それにはもっと良い名前があるはずです。この質問では、ロケールがそれ自体の順序を定義するため、ロケールが有効になっていない状況を具体的に意味します。

過去数年間、私たちは通常、標準のソート順を「ASCIIbetically」と呼んでいました。それはLearningPerlや他の多くの本にあります。ただし、その期間は日付が付けられています。Perlは5.6以降Unicodeに対応しています。ASCIIについて話すのは昔ながらのことです。PerlもUnicodeに対応しているため、文字列を認識しています。sv.cでは、、、およびUTF-8についてPerl_sv_cmp知っています。最初の2つは簡単です。しかし、私は3番目について自信がありません。localebytes

/*
=for apidoc sv_cmp

Compares the strings in two SVs.  Returns -1, 0, or 1 indicating whether the
string in C<sv1> is less than, equal to, or greater than the string in
C<sv2>. Is UTF-8 and 'use bytes' aware, handles get magic, and will
coerce its args to strings if necessary.  See also C<sv_cmp_locale>.

=cut
*/

PerlがUTF-8を使用してソートする場合、実際には何をソートしますか?文字列がエンコードするバイト、文字列が表す文字(おそらくマークを含む?)、または他の何か?これはsv.cの関連行(コミット7844ec1の6698行)だと思います。

 pv1 = tpv = (char*)bytes_to_utf8((const U8*)pv1, &cur1);

私がその権利を読んでいる場合(私のさびたCを使用して)、pv1オクテットに強制され、UTF-8に変換され、次に文字に強制されます(Cの意味で)。これは、UTF-8エンコーディング(つまり、UTF-8がコードポイントを表すために使用する実際のバイト)でソートしていることを意味すると思います。別の言い方をすれば、それは書記素でソートされないということです。私はこれを正しく読んでいるとほぼ確信していると思いますが、あなた方の何人かは私よりもこれについてもっとよく知っています。

それから、次の興味深い行は6708です。

 const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

かつては強制されていたとがpv1、強制されているため、バイトごとに比較されているように見えます。これは、私がこれまでに読んださまざまなドキュメントに基づいてビットを比較しているように見える、で何が起こるのでしょうか?繰り返しになりますが、Unicode正規化ステップのように、bytes-> utf8->char->bytesからの移動で何が欠けているのか疑問に思っています。utf8.cでチェックアウトしても、その質問に答えることはできませんでした。pv2char *void *memcmpPerl_bytes_to_utf8

ちなみに、これはUnicode照合アルゴリズムと同じものかどうか疑問に思っていますか?もしそうなら、なぜUnicode :: Collat​​eが存在するのですか?sort見た目からすると、Perlが標準的な同等性を処理しているとは思いません。

4

2 に答える 2

14

UTF-8には、UTF-8文字列をバイト値に従ってバイトごとにソートすると、コードポイント番号に従ってコードポイントごとにソートするのと同じ順序になるという特性があります。つまり、U+2345のUTF-8表現が辞書式順序でU+1234のUTF-8表現の後にあることを私は見ずに知っています。

正規化に関しては、Perlコアはそれについて何も知りません。さまざまなフォーム間で正確な並べ替えと比較を行うには、すべての文字列をUnicode :: Normalizeで実行し、それらすべてを同じ正規化フォームに変換します。主に私には手がかりがないため、特定の目的にどちらが最適かについてコメントすることはできません。

また、並べ替えは、プラグマが使用されている場合はプラグマcmpの影響を受けます。localePOSIX照合順序を使用します。use locale、8ビットロケール、およびユニコードをすべて一緒に使用することは災害のレシピですが、、、use localeUTF-8ロケール、およびユニコードを使用すると便利に機能するはずです。試したとは言えません。とにかく、 perllocaleperlunicodeには非常に多くの情報があります。

于 2009-11-05T01:06:06.393 に答える
5

質問全体に答えることはできないので、一部に焦点を当てさせてください。

    const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

...かつては強制されていたとがpv1、強制されているため、バイトごとに比較されているように見えます。それは何が起こるのですかpv2char *void *memcmp

かなり。memcmpとの主な違いは次のstrcmpとおりです。

  1. strcmpNULL(すなわち)を検出すると停止し、Perlはスカラーにs'\0'を埋め込むことを許可しますNULL
  2. memcmp多くの場合、より少し速く実行されますstrcmp

しかし、それを除けば、同じ結果が得られます。

于 2009-11-05T01:22:51.867 に答える