5

免責事項:以下のすべてのテキスト(1つの簡単な質問)についてお詫び申し上げますが、すべての情報が質問に関連していると心から思います. それ以外で教えていただけると幸いです。成功した場合、質問と回答が Unicode 狂気の他の人に役立つことを願っています。ここに行きます。

私は utf8 に関する通常高く評価されているすべての Web サイトを読みましたが、特にこれは私の目的には非常に適していますが、SO の他の同様の質問で言及されているような古典も読みました。ただし、仮想ラボにすべてを統合する方法については、まだ知識が不足しています。私はEmacsを使っています

;; Internationalization
(prefer-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)

私の.emacsでは、xtermはで始まりました

 LC_CTYPE=en_US.UTF-8 xterm -geometry 91x58\
-fn '-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO10646-1'

私のロケールは次のとおりです。

LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

私の質問は次のとおりです (回答の一部はアプリケーションの予想される動作である可能性がありますが、それでも理解する必要があるので、ご容赦ください):

次の C プログラムを想定します。

#include <stdio.h>

int main(void) {
  int c;
  while((c=getc(stdin))!=EOF) {
    if(c!='\n') {
      printf("Character: %c, Integer: %d\n", c, c);
    }
  }
  return 0;
}

これを xterm で実行すると、次のようになります。

€
Character: � Integer: 226
Character: �, Integer: 130
Character: �, Integer: 172

(念のため、取得した文字が黒い円内の白い疑問符です)。int は € をエンコードするために必要な 3 バイトの 10 進数表現ですが、なぜ xterm がそれらを適切に表示しないのか正確にはわかりません。

代わりに、マウスパッド、たとえば印刷

Character: â, Integer: 226
Character: ,, Integer: 130 (a comma, standing forU+0082 <control>, why?!)
Character: ¬, Integer: 172

その間、Emacsは表示します

Character: \342, Integer: 226
Character: \202, Integer: 130
Character: \254, Integer: 172

質問: 私ができる最も一般的な質問は次のとおりです。すべてを同じ文字で印刷するにはどうすればよいですか? しかし、私はフォローアップがあると確信しています。

もう一度ありがとう、そしてすべてのテキストについてお詫び申し上げます。

4

3 に答える 3

7

ここでの問題は、古い学校の C ライブラリ呼び出し (getc、printf %c) と UTF-8 が混在しているためです。コードは '€' を構成する 3 バイト (10 進数として 226、130、172) を正しく読み取っていますが、これらの値は個別に有効な UTF-8 エンコードのグリフではありません。

UTF-8 エンコーディングを見ると、整数値 0..127 は元の US-ASCII 文字セットのエンコーディングです。ただし、128..255 (つまり、すべてのバイト) はマルチバイト UTF-8 文字の一部であるため、個別に有効な UTF-8 文字に対応していません。

つまり、1 バイトの '226' はそれ自体では何の意味もありません (3 バイト文字のプレフィックスであるため、予想通り)。このprintf呼び出しは、UTF-8 エンコーディングでは無効な 1 バイトとして出力するため、異なるプログラムはそれぞれ異なる方法で無効な値に対処します。

UTF-8文字がどのバイトで構成されているかを「確認」したいだけだと仮定すると、すでに持っている整数出力に固執することをお勧めします(または、それがより賢明な場合は16進数を使用することもできます)-127バイト以上は有効ではないためunicode を使用すると、異なるプログラム間で一貫した結果が得られる可能性が低くなります。

于 2009-07-17T22:22:52.650 に答える
3

UTF-8 エンコーディングでは、文字列内の 3 バイトが一緒になってユーロ記号 (「€」) を形成します。ただし、C プログラムによって生成されるような単一バイトは、UTF-8 ストリームでは意味がありません。そのため、それらは U+FFFD の「置換文字」または「�」に置き換えられます。

E-macs は賢く、1 バイトが出力ストリームにとって無効なデータであることを認識し、それをバイトの目に見えるエスケープ表現に置き換えます。マウスパッドの出力が本当に壊れています。意味がわかりません。マウスパッドは、個々のバイトが文字を表す CP1252 Windows コードページに戻ります。「コンマ」はコンマではなく、低い曲線の引用符です。

于 2009-07-17T22:24:45.643 に答える
1

あなたが最初に投稿したもの:

Character: � Integer: 226
Character: �, Integer: 130
Character: �, Integer: 172

「正解」です。文字226を印刷し、端末がutf8を予期している場合、端末が実行できることは何もありません。無効なデータを指定しました。シーケンス「226」「スペース」はエラーです。?文字は、どこかに不正な形式のデータがあることを示す良い方法です。

2番目の例を複製する場合は、文字を適切にエンコードする必要があります。

2つの関数を想像してみてください。デコード。文字エンコードとオクテットストリームを受け取り、文字のリストを生成します。エンコード。文字のリストをエンコードして、オクテットストリームを生成します。データが有効な場合、encode / decodeはリバーシブルである必要があります:encode('utf8'、decode('utf8'、 "..."))=="..."。

とにかく、2番目の例では、アプリケーション(「マウスパッド?」)は、ユーロ文字の3オクテット表現の各オクテットを個別のlatin1文字として扱います。オクテットを取得し、latin-1から「文字」(オクテットやバイトではない)の内部表現にデコードしてから、その文字をutf8としてエンコードし、端末に書き込みます。それが機能する理由です。

GNU Recodeをお持ちの場合は、次のことを試してください。

$ recode latin1..utf8
<three-octet representation of the euro character> <control-D>
â¬

これは、utf-8表現の各オクテットをlatin1文字として扱い、それらの各文字を端末が理解できるものに変換することでした。おそらく、これをhdで実行すると、より明確になります。

$ cat | hd
€
00000000  e2 82 ac 0a               |....|
00000004

ご覧のとおり、文字のutf-8表現では3オクテットであり、次に改行です。

再コードの実行:

$ recode latin1..utf8 | hd
€
00000000  c3 a2 c2 82 c2 ac 0a      |.......|
00000007

これは、「latin1」入力文字列のutf-8表現です。端末が表示できるもの。ターミナルに出力すると、ユーロ記号が表示されます。出力しても何も得られません、それは無効です。最後に、を出力すると、キャラクターの「utf-8表現」である「ガベージ」が得られます。

これが紛らわしいと思われる場合はそうです。このような内部表現について心配する必要はありません。文字を操作していて、それらをutf-8端末に出力する必要がある場合は、常にutf-8にエンコードする必要があります。utf-8でエンコードされたファイルから読み取る場合は、アプリケーションで処理する前に、オクテットを文字にデコードする必要があります。

于 2009-07-18T00:22:48.190 に答える