SyncTERMはデフォルトのMacOSターミナルエミュレータとは異なる文字エンコーディングを使用しており、それらは互いに互換性がないことに気づきました。たとえば、ブロック文字をフォーマット文字列で印刷するとします。 IBM Extended ASCII文字エンコードを使用するSyncTERMでは、\261
のような8進エスケープシーケンスを使用します。Terminal.app(およびおそらくiTerm2も)では、これは単に出力します。疑問符。これらの端末はUTF-8を使用するため、\uxxxx
エスケープシーケンスを使用する必要があります。
したがって、ASCIIではない特定の文字をフォーマット文字列で印刷し、文字セットに関係なく、すべてのターミナルエミュレータで機能させたいとします。 terminfoデータベースのエントリを使用すると思いますが、terminfoについてはあまり詳しくありません。ここにいくつかのポインタが必要です。
アプリのロケールをsetlocale(LC_ALL, "")
で初期化してから、nl_langinfo(CODESET)
を呼び出します。これにより、LANG、LC_CTYPE、LC_ALL環境変数から解決された値が得られます。
これはnotターミナルエミュレータが実際にどのように機能するかを示しますが、これはほとんどすべてのアプリケーションが依存しているものです。これにより誤った結果が得られる場合は、システムが正しく構成されておらず、他のほとんどすべてのアプリもターミナルエミュレーターで正しく機能しません。アプリ開発者として、壊れているかどうかを検出して修正しようとするのはあなたの仕事ではありません。正しく設定されていると安全に想定できます。システム管理者、ディストリビューション開発者、またはシステムをハッキングするユーザーとして、ロケール変数とターミナルエミュレータの実際の動作が一致することを確認するのはあなたの仕事です。
ターミナルエミュレータが適切に設計および構成されている場合、環境変数LC_CTYPE
の値がそのエンコーディングと一致する値に設定されていることが保証されます。残念ながら、実際には、LC_CTYPE
のチェックは常に信頼できるとは限りません。設定されていないか間違っている可能性があります。 (他の環境変数がロケール設定を伝達する場合があります。詳細については、 ロケールを何に設定する必要がありますか? を参照してください。
どの文字エンコードが可能性が高いかがわかっている場合は、ヒューリスティックを使用してエンコードを判別できる場合があります。異なるエンコーディングで異なる幅のバイト文字列を表示し、カーソルをどれだけ動かすかを調べます。これは、すべての場合に役立つわけではありません。たとえば、シングルバイトエンコーディングを区別することはできません。しかし、可能性のある2つだけがUTF-8と1つのレガシーエンコーディングである場合、それはうまく機能します。 Shellの起動時に、このようにLC_CTYPE
を設定し、投稿したスクリプトwidthof
を使用して 文字列の表示幅を取得 。 widthof -1
は、UTF-8で2文字を表す4バイトの文字列を表示し、印刷可能なlatin-N文字は3バイトのみです。したがって、幅2はUTF-8(または、私にはありそうもない他のマルチバイトエンコーディング)を意味し、幅3はlatin-N(Nを知る方法がない)を意味し、4はシングルバイトエンコーディングを意味します。 128〜159の範囲の印刷可能な文字。
widthof -1
case $? in
0) export LC_CTYPE=C;; # 7-bit charset
2) locale_search .utf8 .UTF-8;; # utf8
3) locale_search .iso88591 .ISO8859-1 .latin1 '';; # 8-bit with nonprintable 128-159, we assume latin1
4) locale_search .iso88591 .ISO8859-1 .latin1 '';; # some full 8-bit charset, we assume latin1
*) export LC_CTYPE=C;; # weird charset
esac