場合によっては、個々の文字の組み合わせ順序を知る必要があります。通常、次のように表現されます。キャラクタークラス正規表現と同じです[b-d]
。この文字クラスは次のように一致します。キャラクター与えられた範囲内で。
どの個人のb-d
文字は範囲(または他の範囲)内の文字です。
また、C言語環境の組み合わせ順序は各ASCII文字のバイト値であることに注意してください。[ㅏ](33〜126の間の文字のみが表示されます):
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
文字範囲をASCII以上に拡張できますか?
しかし:
ソート順はどうなりますか?個々の文字他の地域では?
(すべてのロケールで)これらのソート順を表示する方法はありますか?
[ㅏ]ASCIIを使用するシステム(ほとんどのシステム)では、他のシステムではEBCDICまたは他のシステムを使用することもできます。
答え1
これにはいくつかの側面があります。ロケールの文字セット内のすべての文字を一覧表示し、グラフィック文字(33〜126文字のASCII文字)を選択してソートする必要があります。
文字の並べ替え順序について話すのが妥当であるのか、それとも定義されたことがあるのかについての質問もあります。最後のポイントから始めます。
POSIX校正アルゴリズム
、または、シェルグローブまたは/、文字列比較演算子によって実装され使用されるC / POSIXソートアルゴリズム、およびより一般的にはPOSIXシステムでユーザーのロケールに基づいてテキストをソートするほとんどのツールについて話しているstrcoll()
場合点に注意してください。sort
ls
awk
expr
<
>
ひも。
GNU システムの en_US.UTF-8 ロケールでは、é
単一é
文字で構成される文字列がソートされます。後ろに単一文字で構成される文字列e
、Stéphane
ソート済み今後 Stephanie
。 cs_CZ.UTF-8ロケールでは、c
との間でソートしますが、間ではソートしません。b
d
ch
h
i
対照アルゴリズムは、個々の文字ではなく文字列全体を考慮します。したがって、個別に比較するときに文字の順序を知ることは、その文字を含む文字列がどのように比較されるかを必ずしも知らせるわけではありません。
このアルゴリズムは、多くの実際の言語(辞書、電話帳など)などの文字列を比較するように設計されています。様々な文化の中で、ソートのすべての微妙さを扱うのはかなり単純です。集中治療室、より多くのアルゴリズムを実装しますが)ほとんどの場合は十分です。
このアルゴリズムでは要素の構成、これには文字だけでなく、韓国語のアルファベットやチェコ語のマルチパート文字などの文字の組み合わせも含まれます。ch
あるいは、一部のシステムでは、組み合わせの後に結合された予音(U + 0301)が複数の割り当てられた形式é
で表示されます。e
重量。
そして完全な文字列比較は、最初の重みから最後の重みまで、順番に各重みを使用して実行されます。
たとえば、このen_US.UTF-8
GNU ロケールでは、 、 、E
ともに同じé
基本重みを持ちます。そしてに分解e
É
Stéphane
Stephanie
<S><t><é><p><h><a><n> <e>
<S><t><e><p><h><a><n> <i><e>
要素の組み合わせ(ここでは文字ごとに1つ)。
現時点では、n
2つの文字列の対照要素は同じ主重みを持っていますが、の主i
重みはe
sより大きいので、Stephanie
ソート後に二次Stéphane
重みを考慮する必要はありません。
これでStephane
、vsのStéphane
場合は、基本重みを比較するときに等しくソートされるので、二次重みを考慮する必要があります。/usr/share/i18n/locales/iso14651_t1_common
en_US.UTF-8ロケールをそのまま使用してGNUシステムを調べると、次のことがわかります。
<BAS> # 15
[...]
<ACA> # 18
[...]
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U00E9> <e>;<ACA>;<MIN>;IGNORE # 260 é
ラテンアルファベット文字の場合、発音区別符号を比較するために補助重みが使用される。デフォルトの文字(BAS
)は急性アクセント()のある文字の前にありますACA
。したがって、Stéphane
順序はにあります。と比較するには、Stephane
英語で大文字が小文字の後にある3番目の重みに達する必要があります(たとえば、エストニア語とは対照的に)。STÉPHANE
Stéphane
IGNORE
また、最初の比較では、主な重みが考慮または考慮されていない空白や句読点などの英数字以外の文字もあります(de facto
これらの文字はおよび間に並べられますが、空白が間に並べられるという意味ではありません)。deface
degree
f
g
$'STE\u0301HANE'
vsでは、Stéphane
一部のシステム(Solarisなど)は、最後の文字が(U + 00C9)文字であることをE\u0301
除いて、同じ重みを持つ対照要素として扱いますが、他のシステムはそれを句読点として処理して結果を提供します。 。良いです(以前のものと同じです)。É
\u0301
$'STE\u0301HANE'
Stephane
一つでもないみんな注文する
GNUシステムではU + 0301のソート順序も定義されていません。この場合、何千もの文字があります。。私は丸められた数字(U + 2460 ... U + 2473)を例として使用したいと思います。なぜなら、この数字は明らかにソート順を持つべきですが、そうではないからです。
$ touch ① ② ③ ④ ⑤
$ ls
④ ③ ⑤ ② ①
$ ls | sort -u
④
実際には、他の文字と同じ重みを持つように定義されたいくつかの文字もあります(たとえば、 Ǝ
ここƏ
でƐ
は順序はすべて同じです)。
sort
したがって、一部の実装で実行する場合を除いて、一部のロケールでは、ランダムな文字をソートすることは実際には不可能です。これは、POSIX 仕様の次のメジャーバージョンの要件になります。)、memcmp()
同じ順序の文字に対して同様の比較を実行できます。
ロケール文字セットのすべてのグラフィック文字のリスト
ロケールごとに異なる文字セットを使用できます。
文字セットには3つの主なカテゴリがあります。 ASCIIやiso-8859-xなどのシングルバイト文字セット(各バイトは文字に対応)(一部は定義されていない場合があります)、文字が異なるバイト数でエンコードされているUTF-8、GB18030、BIG5、またはEUCJPなどステートフルバイト
最後のカテゴリは最近ロケールでほとんど使用されず、管理が難しいことが多いので、今は無視しても構いません。
C ロケールは本質的に単一バイト文字セットを持つことが保証されます。 EBCDICベースではないシステムで一般的に見られますが、必ずしもASCIIである必要はありません。
一部のスクリプト(英語で使用されるラテンスクリプトなど)は左から右に、他のスクリプトは右から左に書かれているため、これらの他のスクリプト(一部の文字セットでサポートされている)の文字は同じ行にあります。必ずしも良い考えではありません。
キャラクターの組み合わせも同様ですが、結局ランダムなキャラクターに組み合わせて合わされることになります。
また、Unicodeなどの一部の文字セットは引き続き進化しています。現在、コードポイントの範囲は0..0xD7FF、0xE000..0x10FFFFに固定されていますが、ほとんどはまだ割り当てられておらず、新しいバージョンのUnicodeごとに新しいコードポイントの範囲が割り当てられ、システムベンダーはこれに合わせて努力しています。
graph
として分類された文字は、ISO / IEC TR 14652(2002)の後継であるISO / IEC 30112テクニカルレポート(2014)に記載されています。 GNUロケールはこれに従うようですが、他のロケール(FreeBSD / Solarisなど)はそうではありません。しかし、私にはあまり意味がないようだから、彼らを非難するわけではありません。たとえば、ほとんどのスペース文字は除外されますが、U+00A0(単純スペース)、U+2007(数値スペース)、またはU+200B(幅0のスペース)は除外されます。私の考えにはキャラクターが含まれていると思います。コントロールU+200C..U+200F, U+202D, U+202E...² のような文字カバーは右から左へこのQ&Aで重要なのは、文字の順序が左から右に変わることです。
$ printf '%b\n' '\u202E' a b c | sort | paste -sd '\0' -
abc
(一部のブラウザではサポートされているかどうかcba
、他のブラウザではサポートされているかどうかが表示されますabc
)。
また、ほとんどのコンテンツが含まれます。商標数値何千もの使用システムに描画できるのはもちろん、割り当てられる可能性もない文字です。
シングルバイト文字セット(GNUシステムではlocale ctype-mb-cur-max
1を返す文字セット)の場合、グラフィック文字のリストはすべての255バイト値を繰り返す必要があります(最初を無視すると、各文字セットのNULはグラフィック文字セットではありません。)問題が発生する可能)と一致させます[[:graph:]]
。
awk
たとえば、次のようにできます。
awk '
BEGIN{
for (i = 1; i < 256; i++) {
c = sprintf("%c", i)
if (c ~ /[[:graph:]]/) print c
}
}' | sort | paste -sd '\0' -
iso8859-7 シングルバイト文字セットを使用するギリシャ語ロケールでは、el_GR.iso88597
以下が提供されます。
`^¨~<=>¦°_-,;:!?/.·'ʽʼ"«»()[]{}§©@$£¤¥*\&#%+±ª―΄΅0½12²3³456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZΑαΆάΒβΓγΔδΕεΈέΖζΗηΉήΘθΙιΊίΪϊΐΚκΛλΜμΝνΞξΟοΌόΠπΡρΣσςΤτΥυΎύΫϋΰΦφΧχΨψΩωΏώ
(後に続く切り捨て防止スペースは、GNUロケールの「グラフィック」として誤って分類されます。)
この方法はマルチバイト文字では使用できません。
または、文字セットエンコーディングをiconv
サポートしている場合は、すべてのUnicodeコードポイントを32ビットのビッグエンディアン数で生成し、それをロケールの文字セットに変換できます。UCS-4BE
UTF32BE
perl -e 'print pack("L>*", $_, 10) for 1..0xd7ff, 0xe000..0x10ffff' |
iconv -cf UCS-4BE |
grep '[[:graph:]]' |
sort
またはUTF-8をサポートしている場合:
perl -C -M-warnings=nonchar -le 'print chr$_ for 1..0xd7ff, 0xe000..0x10ffff' |
iconv -cf UTF-8 |
grep '[[:graph:]]' |
sort
(上記の問題を回避し、行が長すぎるのを防ぐために、1行に1文字ずつ予約してください。)
これは、Unicode(および対応するエンコード)が他のすべての可能な文字セットの文字を含むように設計されているため、すべての文字セット内のすべての文字には常にUnicodeコードポイントがあります。最新のシステムは、実際にはUnicodeの点で文字セットを定義し、通常はwchar_t
Unicodeコードポイントに対応します。
上記のように、ソートはソートとmemcmp()
同じ文字比較に基づく比較を使用しますstrcoll()
。シングルバイト文字セットの場合、その文字セット内のコードポイントに基づいてソートされます。 UTF-8の場合、UTF-8には特定の属性があるため、Unicodeコードポイントに基づいてソートされます。他のUnicodeエンコーディング(中国語GB18030や他のマルチバイト文字セットなど)の場合、これは多少ランダムに表示されることがあります。
それにもかかわらず、これは、ソート順が同じ2つのロケールの場合、そのsort
ロケールが異なる文字セットを使用すると出力が異なることを意味します。
例えば、① ② ③ ④ ⑤ ⑥ ⑦ ─ ⑩⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ 丸められた数字に戻ると。 Unicodeはこれを対応する順序(コードポイント0x2460〜0x2473)で指定します。 GNUロケールでは順序は定義されていません(①が②よりも前も後もありません)。 UTF-8を使用するロケールでは、UTF-8の順序はUnicodeコードポイントの順序に従うので、①の後に②をソートします。ただし、GB18030(中国の別のUnicodeエンコーディング)を使用するzh_CN.gb18030などのロケールでは、文字がバイトレベルでエンコードされる方法に応じて、⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳123456789⑩このエラーこれにより、手順は①②②③④⑤⑥⑧⑩⑮⑯⑰⑱⑲⑳⑪⑫⑬⑭)です。
照合順序に従って文字列の文字を並べ替えるには、次のようにしますzsh
。
printf "%s\n" ${(j::)${(s::o)string}}
zshは変数にNUL文字を含めることができますが、strcoll()
これらの文字では機能しません。zsh
この問題を解決しようとしましたが、完璧ではない。
文字列に同じソート順を持つ別の文字が含まれている場合、結果は定義されません。
^2019年編集新しいバージョンのGNU libcでは、①②②③④⑤の順序が修正されましたが、2.30現在95%以上の文字がまだ定義されている順序はありません。
答え2
Bashとzshでは、一連の数字を生成するのは簡単です。
$ printf '\\x%x' {53..63}
\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f
UNICODE数値を文字に変換するのも簡単です。
$ printf '%b' "$(printf '\\U%x' {53..63})"
56789:;<=>?
これはbashコーダーのための贈り物であり、\UXXXXXXXX
制限はありません。コード0から10FFFF(10進数で1114111)まで動作します。
したがって、次の簡単なコードを使用して最初の127文字を生成できます。
$ printf '%b' "$(printf '\\U%x' {0..127})" | hd
00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./|
00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?|
00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|
00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\]^_|
00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno|
00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.|
00000080
各文字にNUL(0x00)文字を追加し、sort -zを使用してソート順を表示できます。
$ printf '%b' "$(printf '\\U%x\\0' {0..127})" | sort -z
`^~<=>| _-,;:!?/.'"()[]{}@$*\&#%+
▒▒123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
そして、NULを削除して数字の順序を確認してください。
$ printf '%b' "$(printf '\\U%x\\0' {0..127})" | sort -z | tr -d '\0' | hd
00000000 60 5e 7e 3c 3d 3e 7c 20 5f 2d 2c 3b 3a 21 3f 2f |`^~<=>| _-,;:!?/|
00000010 2e 27 22 28 29 5b 5d 7b 7d 40 24 2a 5c 26 23 25 |.'"()[]{}@$*\&#%|
00000020 2b 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |+...............|
00000030 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
00000040 7f 30 31 32 33 34 35 36 37 38 39 61 41 62 42 63 |.0123456789aAbBc|
00000050 43 64 44 65 45 66 46 67 47 68 48 69 49 6a 4a 6b |CdDeEfFgGhHiIjJk|
00000060 4b 6c 4c 6d 4d 6e 4e 6f 4f 70 50 71 51 72 52 73 |KlLmMnNoOpPqQrRs|
00000070 53 74 54 75 55 76 56 77 57 78 58 79 59 7a 5a |StTuUvVwWxXyYzZ|
0000007f
Cロケールの順序との違いに注意してください。
$ printf '%b' "$(printf '\\U%x\\0' {0..127})" | LC_COLLATE=C sort -z | tr -d '\0' | hd
00000000 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
00000010 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000020 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000030 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 |123456789:;<=>?@|
00000040 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 |ABCDEFGHIJKLMNOP|
00000050 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 |QRSTUVWXYZ[\]^_`|
00000060 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|
00000070 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |qrstuvwxyz{|}~.|
0000007f
バイトはASCIIの範囲外の128個の値を持つことができ、utf8として印刷されます。降伏(データソートでソートされていません):
$ printf '%b' "$(printf '\\U%x' {125..255})"
}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
組み合わせ順序の同じ範囲は次のとおりです(最初の文字は急性アクセントであり、小文字と大文字のコレクションが交互に表示されます)。
$ printf '%b' "$(printf '\\U%x\\0' {125..255})" | sort -z
´¨~÷׬¦°µ¯¡¿·¸«»}§¶©®¤¢£¥±¼½¾¹²³áÁàÀâÂåÅäÄãêæÆ
çÇðÐéÉèÈêÊëËíÍìÌîÎïÏñÑóÓòÒôÔöÖõÕøغßúÚùÙûÛüÜýÝÿþÞ
範囲が広がると、ソート順がさらに複雑になります。
$ printf '%b' "$(printf '\\U%x\\0' {0..500})" | sort -z | tr -d '\0'
´`^¨~÷×<=>¬|¦°µ _¯-,;:!¡?¿/.·¸'"«»()[]{}§¶©®@¤¢$£¥*\&#%+
±ƀƂƃƄƅƉƋƌƍƑƒƔƖƗƚƛƜƝƞƤƥƦƧƨƩƪƫƬƭƮƱƲƸƹƺƻƼƽƾǀǁǂǃ
▒▒0¼½¾1¹2²3³456789aAáÁàÀăĂâÂǎǍåÅäǟÄǞãÃǡǠąĄāĀªæǣÆǢ
bBƁcCćĆĉĈčČċĊçÇƈƇdDďĎđĐƊðÐdzDzDZdžDžDŽeEéÉèÈĕĔêÊěĚëËėĖęĘēĒǝƎƏƐ
fFgGǴğĞĝĜǧǦġĠǥǤģĢƓƣƢhHĥĤħĦƕiIíÍìÌĭĬîÎǐǏïÏĩĨįĮīĪıİijIJ
jJĵĴǰkKǩǨķĶƙƘlLĺĹľĽŀĿłŁļĻljLjLJmMnNńŃňŇñÑņŅʼnŋŊnjNjNJ
oOóÓòÒŏŎôÔǒǑöÖƟőŐõÕøØǫǭǪǬōŌơƠºƆœŒpPqQĸrRŕŔřŘŗŖ
sSśŚŝŜšŠşŞſßtTťŤŧŦţŢuUúÚùÙŭŬûÛǔǓůŮüǘǜǚǖÜǗǛǙǕűŰũŨųŲūŪưƯ
vVwWŵŴƿxXyYýÝŷŶÿŸƴƳzZźŹžŽżŻƶƵþÞƷǯǮ
printfがutf8で文字をバイトペアに生成し、sort(純粋なCロケールを使用)がバイトソートを試みるため、これらの大きな文字グループをソートすることは純粋なCロケールでは不可能です。それ以外の場合は、\U…
Cロケールでprintfが失敗します。必要なのは、1バイトに入ることができる256文字よりも多くの文字を許可する同等のロケールです。
$ LC_ALL=C.UTF-8 printf "$(printf '\\U%x' {32..500})" | sort
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ
[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·
¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñò
óôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭ
ĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨ
ũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣ
ƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞ
ǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ
答え3
照合順序はロケール・ファイルによって定義されます。以下は、en_USロケールのすべてのASCII文字シーケンスです。
codes=$(for i in {32..126}; do echo "u$(printf '%04x' "$i")"; done)
grep_patterns=$(echo "$codes" | sed 's/^/^</; s/$/>/')
codes_locale=$(grep -oif - <<<"$grep_patterns" /usr/share/i18n/locales/iso14651_t1_common | tr -d '<>')
# "ASCII sequence"
for c in $codes; do echo -ne "\\$c"; done; echo
# "en_US sequence"
for c in $codes_locale; do echo -ne "\\$c"; done; echo
# OUTPUT:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
# !"#%&'()*+,-./:;<=>?@[\]^_`{|}~$0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
順序順序はソート順序と同じではないことを覚えておく必要があります。ソート中は追加のルールが適用されます。