Emacs, xterm, 마우스패드, C, 유니코드 및 UTF-8:모든 것을 이해하려고 노력 중

StackOverflow https://stackoverflow.com/questions/1145889

문제

부인 성명:아래의 모든 텍스트(단순한 질문 하나)에 대해 사과드립니다. 하지만 모든 정보가 질문과 관련이 있다고 진심으로 생각합니다.다른 방법을 배우게 되어 기쁩니다.만약 성공한다면 질문과 답변이 유니코드 광기에 빠진 다른 사람들에게 도움이 되기를 바랄 뿐입니다.여기 간다.

나는 utf8에 관해 일반적으로 높은 평가를 받는 모든 웹사이트를 읽었습니다. 특히 이 하나 내 목적에 매우 좋지만 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

질문:제가 물어볼 수 있는 가장 일반적인 질문은 다음과 같습니다.동일한 문자를 인쇄하려면 어떻게 해야 합니까?하지만 후속 조치가 있을 것이라고 확신합니다.

다시 한 번 감사드리며, 모든 내용에 대해 사과드립니다.

도움이 되었습니까?

해결책

자, 여기에서 문제는 구식 C 라이브러리 통화 (getc, printf %c)와 UTF-8을 혼합했기 때문입니다. 코드는 10 진수로 '€'-226, 130 및 172를 구성하는 세 바이트를 올바르게 읽고 있지만 이러한 값은 개별적으로 유효한 UTF -8 인코딩 된 글리프가 아닙니다.

당신이 보면 UTF-8 인코딩, 정수 값 0..127은 원래 US-ASCII 문자 세트의 인코딩입니다. 그러나 128..255 (즉, 모든 바이트)는 Multibyte UTF-8 문자의 일부이므로 유효한 UTF-8 문자에 해당하지 않습니다.

다시 말해서 단일 바이트 '226'은 그 자체로는 아무 의미가 없습니다 (예상대로 3 바이트 문자의 접두사이므로). 그만큼 printf Call은 UTF-8 인코딩으로 유효하지 않은 단일 바이트로 인쇄하므로 각각의 다른 프로그램은 다른 방식으로 잘못된 값에 대처합니다.

바이트 UTF -8 문자가 어떤 바이트를 '확인'하고 싶다고 가정하면, 이미 가지고있는 정수 출력을 고수하는 것이 좋습니다 (또는 더 현명한 경우 16 진수를 사용 할 수도 있습니다) -> 127 바이트가 유효하지 않으므로 유효하지 않기 때문입니다. 유니 코드 다른 프로그램에서 일관된 결과를 얻을 수는 없습니다.

다른 팁

UTF-8 인코딩은 3 바이트가 문자열로 함께 함께 사용한다고 말합니다. 그러나 C 프로그램에서 생성 된 것과 같은 단일 바이트는 UTF-8 스트림에서 의미가 없습니다. 그렇기 때문에 U+FFFD "대체 문자"또는 '�'로 대체됩니다.

e-macs는 똑똑하며 단일 바이트가 출력 스트림의 유효하지 않은 데이터임을 알고 있으며 바이트의 가시 탈출 표현으로 대체합니다. Mousepad 출력은 실제로 깨졌습니다. 나는 그것을 이해할 수 없습니다. Mousepad는 개별 바이트가 문자를 나타내는 CP1252 Windows CodePage로 돌아갑니다. "쉼표"는 쉼표가 아니며 낮은 곡선 인용구.

가장 먼저 게시한 내용은 다음과 같습니다.

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

"정확한" 대답입니다.문자 226을 인쇄하고 터미널에서 utf8을 예상하면 터미널에서 수행할 수 있는 작업이 없으며 잘못된 데이터를 제공한 것입니다."226" "공백" 시퀀스는 오류입니다.?문자는 어딘가에 잘못된 형식의 데이터가 있음을 보여주는 좋은 방법입니다.

두 번째 예를 복제하려면 문자를 올바르게 인코딩해야 합니다.

두 가지 기능을 상상해보세요.디코드(decode)는 문자 인코딩과 옥텟 스트림을 받아 문자 목록을 생성합니다.인코딩은 문자 목록을 인코딩하여 옥텟 스트림을 생성합니다.데이터가 유효하면 인코딩/디코딩을 되돌릴 수 있어야 합니다.인코딩( 'utf8', 디코드( 'utf8', "..." ) ) == "...".

어쨌든, 두 번째 예에서 애플리케이션("마우스패드?")은 유로 문자의 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로 인코딩된 파일을 읽는 경우 애플리케이션에서 처리하기 전에 옥텟을 문자로 디코딩해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top