C/C++ 프로그램에서 터미널이 사용하는 문자 인코딩을 어떻게 결정합니까?

C/C++ 프로그램에서 터미널이 사용하는 문자 인코딩을 어떻게 결정합니까?

SyncTERM은 기본 MacOS 터미널 에뮬레이터와 다른 문자 인코딩을 사용하며 서로 호환되지 않는 것으로 나타났습니다. 예를 들어 형식 문자열에 블록 문자를 인쇄한다고 가정해 보겠습니다. IBM 확장 ASCII 문자 인코딩을 사용하는 SyncTERM에서는 8진수 이스케이프 시퀀스를 사용합니다 \261. 예를 들어 Terminal.app(및 아마도 iTerm2)에서는 물음표만 인쇄합니다. 이러한 터미널은 UTF-8을 사용하므로 \uxxxx이스케이프 시퀀스를 사용해야 합니다 .

ASCII가 아닌 특정 문자를 형식 문자열로 인쇄하고 문자 세트에 관계없이 모든 터미널 에뮬레이터에서 작동하기를 원한다고 가정하십시오. 나는 당신이 데이터베이스의 terminfo 항목을 사용할 것이라고 추측하지만 나는 terminfo에 익숙하지 않습니다. 여기에 지침이 필요합니다.

답변1

짧은:

  • terminfo는 당신을 그곳으로 데려가지 않을 것이고 도움이 되지 않을 것입니다.
  • 터미널에서 사용되는 실제 인코딩을 확인할 수 있는 신뢰할 수 있는 방법은 없습니다.
  • 터미널에서 사용할 인코딩을 알고 있다면 유니코드 리터럴로 시작하는 것이 좋습니다.
  • 사용자는 어떤 로케일이 적절한지, 터미널이 어떤 인코딩을 수행할 수 있는지 알아야 합니다.
  • C 표준에는 모든 Unix 계열 플랫폼에서 사용할 수 있는 "와이드" 문자를 변환하는 기능이 있습니다(예를 들어 다음을 참조하세요).setlocale,wcrtomb그리고wcsrtombs)

답변2

setlocale(LC_ALL, "")then 호출을 사용하여 애플리케이션의 로케일을 초기화합니다 nl_langinfo(CODESET). 그러면 LANG, LC_CTYPE, LC_ALL 환경 변수에 대해 확인된 값이 제공됩니다.

이것은 실제로아니요터미널 에뮬레이터가 실제로 어떻게 작동하는지 알려 주지만 거의 모든 애플리케이션이 이에 의존합니다. 이로 인해 잘못된 결과가 나타나면 시스템이 잘못 구성된 것이며 거의 모든 다른 응용 프로그램도 터미널 에뮬레이터에서 제대로 작동하지 않습니다. 애플리케이션 개발자로서 귀하의 임무는 문제가 있는지 감지하고 수정하려고 시도하는 것이 아닙니다. 자신에게 맞게 올바르게 설정되었다고 안전하게 가정할 수 있습니다. 시스템 관리자, 배포 개발자 또는 시스템 해킹 사용자로서 귀하의 임무는 로케일 변수와 터미널 에뮬레이터의 실제 동작이 일치하는지 확인하는 것입니다.

답변3

터미널 에뮬레이터가 제대로 설계되고 구성되면 환경 변수의 값이 LC_CTYPE해당 인코딩과 일치하는 값으로 설정됩니다. 불행하게도 실제로는 검사가 LC_CTYPE항상 신뢰할 수 있는 것은 아닙니다. 설정되지 않았거나 잘못되었을 수 있습니다. (다른 환경 변수는 로케일을 전달할 수 있습니다.로케일을 무엇으로 설정해야 하나요? 이것이 어떤 영향을 미칠까요?더 알아보기. )

가능한 문자 인코딩에 대한 아이디어가 있다면 경험적 방법을 통해 인코딩을 결정할 수 있습니다. 다양한 인코딩으로 다양한 너비의 바이트 문자열을 표시하고 커서가 얼마나 이동하는지 알아보세요. 이는 모든 경우에 도움이 되지 않습니다. 예를 들어 단일 바이트 인코딩을 구별할 수 없습니다. 그러나 UTF-8과 이전 인코딩이 두 가지 가능성뿐이라면 괜찮습니다. 쉘 시작 시 게시한 LC_CTYPE스크립트를 사용하여 이런 방식으로 설정했습니다.widthof문자열의 표시 너비를 가져옵니다.. widthof -1UTF-8로 2자를 나타내는 4바이트 문자열을 표시합니다. 이 중 3바이트만 인쇄 가능한 라틴-N 문자입니다. 따라서 너비 2는 UTF-8(또는 나에게는 가능성이 없는 다른 멀티바이트 인코딩)을 의미하고, 너비 ​​3은 라틴-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

관련 정보