UTF-16을 유해한 것으로 간주해야합니까?


432

아마도 논란의 여지가있는 질문이 무엇인지 물어볼 것입니다. "가장 인기있는 인코딩 중 하나 인 UTF-16이 유해한 것으로 간주되어야합니까?"

왜이 질문을합니까?

UTF-16이 실제로 가변 길이 인코딩이라는 사실을 알고있는 프로그래머는 몇 명입니까? 이것은 대리 쌍으로 표현되는 코드 포인트가 두 개 이상의 요소를 취하는 것을 의미합니다.

알아; 많은 애플리케이션, 프레임 워크 및 API는 Java의 문자열, C #의 문자열, Win32 API, Qt GUI 라이브러리, ICU 유니 코드 라이브러리 등과 같은 UTF-16을 사용합니다. BMP 외부 문자 (두 UTF-16 요소를 사용하여 인코딩해야하는 문자)

예를 들어 다음 문자 중 하나를 편집하십시오.

설치 한 글꼴에 따라 일부를 놓칠 수 있습니다. 이 문자들은 모두 BMP (Basic Multilingual Plane) 외부에 있습니다. 이러한 문자가 보이지 않으면 유니 코드 문자 참조 에서 해당 문자를 살펴볼 수도 있습니다.

예를 들어, Windows에서 이러한 문자를 포함하는 파일 이름을 작성하십시오. UTF-16을 사용하는 다른 응용 프로그램에서 어떻게 작동하는지 보려면 "백 스페이스"를 사용하여 이러한 문자를 삭제하십시오. 나는 몇 가지 테스트를했는데 결과가 매우 나쁘다.

  • Opera에서 편집에 문제가 있습니다 (백 스페이스에서 2 번 누르기 삭제 필요).
  • 메모장에서 올바르게 처리 할 수 ​​없습니다 (백 스페이스에서 두 번 눌러 삭제해야 함).
  • 창 대화 상자에서 파일 이름 편집이 깨짐 (백 스페이스에서 2 번 누르기 필요)
  • 모든 QT3 응용 프로그램은이를 처리 할 수 ​​없습니다 . 하나의 기호 대신 두 개의 빈 사각형을 표시하십시오.
  • u'X'!=unicode('X','utf-16')X는 BMP 외부의 문자 인 경우 일부 플랫폼에서 직접 사용될 때 이러한 문자를 잘못 인코딩 합니다.
  • Python 2.5 유니 코드 데이터는 파이썬이 UTF-16 유니 코드 문자열로 컴파일 될 때 이러한 문자에 대한 특성을 가져 오지 못합니다.
  • StackOverflow는 유니 코드 문자로 직접 편집하면 텍스트에서 이러한 문자를 제거하는 것으로 보입니다 (이 문자는 HTML 유니 코드 이스케이프를 사용하여 표시됨).
  • MaxLength로 제한되면 WinForms TextBox가 잘못된 문자열을 생성 할 수 있습니다 .

UTF-16을 사용하는 많은 응용 프로그램에서 이러한 버그를 쉽게 찾을 수 있습니다.

그렇다면 ... UTF-16이 해로운 것으로 간주되어야한다고 생각하십니까?


64
실제로 정확하지 않습니다. "ש", "ָ"및 "ׁ", "vel"으로 구성되는 복합 문자 "vovel"을 쓴 경우 각 문자를 제거하는 것이 논리적이므로 "키를 누르면 하나의 코드 포인트가 제거됩니다. "del"을 누르면 "백 스페이스"를 입력하고 vovel을 포함한 모든 문자를 제거합니다. 그러나 불법적 인 텍스트 상태, 즉 불법 코드 포인트를 생성하지 마십시오 . 따라서 백 스페이스 키를 누르고 잘못된 텍스트를 얻는 상황이 올바르지 않습니다.

41
CiscoIPPhone : 버그가 "다양한 사람들에 의해 여러 번보고"되고 몇 년 후 개발자가 개발자 블로그에 "믿거 나 말거나 행동은 대부분 의도적입니다!"라고 쓴다. 나는 그것이 아마도 최고의 디자인 결정이 아니라고 생각하는 경향이 있습니다. :-) 의도적이라고해서 이것이 버그가 아님을 의미하지는 않습니다.

145
좋은 포스트. UTF-16은 실제로 "두 세계 중 최악"입니다. UTF8은 가변 길이이며 모든 유니 코드를 포함하며 원시 코드 포인트와의 변환 알고리즘이 필요하며 ASCII로 제한되며 엔디안 문제가 없습니다. UTF32는 고정 길이이며 변환이 필요하지 않지만 더 많은 공간을 차지하며 엔디안 문제가 있습니다. 지금까지는 내부적으로 UTF32를 사용하고 직렬화에 UTF8을 사용할 수 있습니다. 그러나 UTF16에는 이점이 없습니다. 엔디 언에 따라 다르며 가변 길이이며 많은 공간이 필요하며 ASCII와 호환되지 않습니다. UTF16을 올바르게 처리하는 데 필요한 노력은 UTF8에 더 잘 사용될 수 있습니다.
Kerrek SB 2016 년

26
@Ian : UTF-8 은 UTF-8과 같은 경고가 없습니다 . UTF-8로 대체 할 수 없습니다. UTF-8은 그렇지 않은 것으로 가장하지만 UTF-16을 사용하는 대부분의 프로그래머는 잘못 사용하고 있습니다. 알아. 나는 그들을 몇 번이고 또 다시 또 다시 보았다.
tchrist

18
또한 UTF-8은 모든 사람이 가변 너비 인코딩으로 취급하기 때문에 문제가 없습니다. UTF-16에 문제가있는 이유는 모든 사람이 고정 너비 인코딩으로 취급하기 때문입니다.
Christoffer Hammarström

답변:


340

이것은 오래된 대답입니다. 최신 업데이트는 UTF-8 Everywhere
참조하십시오 .

의견 : 예, UTF-16은 유해한 것으로 간주해야합니다 . 그것이 존재하는 이유는 얼마 전에 widechar가 UCS-4가 될 것이라고 오도 된 믿음이 있었기 때문입니다.

UTF-8의 "anglo-centrism"에도 불구하고 텍스트에 유일하게 유용한 인코딩으로 간주되어야합니다. 프로그램의 소스 코드, 웹 페이지 및 XML 파일, OS 파일 이름 및 기타 컴퓨터 간 텍스트 인터페이스는 존재하지 않았어야한다고 주장 할 수 있습니다. 그러나 그들이 할 때 텍스트는 인간 독자만을위한 것이 아닙니다.

반면, UTF-8 오버 헤드는 지불해야하는 비용이 적지 만 상당한 이점이 있습니다. 로 문자열을 전달하는 알지 못하는 코드와의 호환성과 같은 장점 char*. 이것은 좋은 일입니다. UTF-8보다 SHUTTER 인 유용한 문자는 UTF-8보다 적습니다.

다른 모든 인코딩은 결국 죽을 것이라고 믿습니다. 이것은 MS-Windows, Java, ICU, python이 그것을 좋아하는 것으로 사용하지 않는 것을 포함합니다. 오랜 연구와 토론 끝에 회사 의 개발 규칙은 OS API 호출을 제외한 모든 곳에서 UTF-16을 사용하는 것을 금지했으며 이는 응용 프로그램의 성능의 중요성과 Windows를 사용한다는 사실에도 불구하고 마찬가지입니다. 항상 가정 된 UTFF8 std::string을 기본 UTF-16 으로 변환하기 위해 변환 기능이 개발되었으며 , Windows 자체 가 제대로 지원하지 않습니다 .

" 필요한 곳에 필요한 것을 사용하십시오 "라고 말하는 사람들에게는 모든 곳에서 동일한 인코딩을 사용하는 데 큰 이점이 있으며 그렇지 않으면 다른 이유가 없습니다. 특히 wchar_tC ++에 추가 하는 것은 실수 라고 생각하고 C ++ 0x에 유니 코드를 추가 한 것도 마찬가지입니다. STL 구현에서 요구해야 할 것은 모든 std::string또는 char*매개 변수가 유니 코드 호환으로 간주 된다는 것입니다.

또한 " 원하는 것을 사용하십시오 "접근 방식 에 위배 됩니다. 나는 그러한 자유의 이유가 없다. 텍스트의 주제에 대해 혼동이 많으므로이 모든 깨진 소프트웨어가 생깁니다. 위에서 말했듯이, 프로그래머는 UTF-8에 대한 적절한 합의에 따라 합의에 도달해야한다고 확신합니다. (나는 ASCII가 아닌 국가에서 왔으며 Windows에서 자랐으므로 마지막으로 종교적 근거를 기반으로 UTF-16을 공격 할 것으로 예상됩니다).

Windows에서 텍스트를 작성하는 방법과 컴파일 타임 검사 된 유니 코드 정확성, 사용 편의성 및 코드의 다중 플랫폼 향상을 위해 다른 사람들에게 권장하는 것에 대한 자세한 정보를 공유하고 싶습니다. 이 제안은 Windows에서 유니 코드를 사용하는 적절한 방법으로 일반적으로 권장되는 것과 다릅니다. 그러나 이러한 권장 사항에 대한 심도있는 연구를 통해 동일한 결론을 얻었습니다. 그래서 여기에 간다 :

  • UTF-16을 허용하는 API에 인접한 점 이외의 곳을 사용 wchar_t하거나 std::wstring다른 곳에서 사용하지 마십시오 .
  • 사용하지 마십시오 _T("")또는 L""UTF-16 리터럴은 (이러한 IMO UTF-16 중단의 일환으로, 표준에서주의해야한다).
  • 유형, 함수 또는에 민감한 이들의 유도체 사용하지 마십시오 _UNICODE과 같은 상수, LPTSTR또는 CreateWindow().
  • 그러나 WinAPI에 문자열을 자동 컴파일 _UNICODE하는 것을 피하기 위해 항상 정의char*
  • std::strings그리고 char*어디 프로그램에서 UTF-8로 간주됩니다 (그렇지 않으면 말했다하지 않은 경우)
  • std::stringchar * 또는 string literal을에 전달할 수 는 있지만 모든 문자열은 convert(const std::string &)입니다.
  • widechars ( LPWSTR) 를 허용하는 Win32 함수 만 사용하십시오 . LPTSTR또는을 ( 를) 수락하는 사람은 절대 아닙니다 LPSTR. 이 방법으로 매개 변수를 전달하십시오.

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())
    

    (정책은 아래의 변환 기능을 사용합니다.)

  • MFC 문자열로 :

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
    
  • Windows에서 파일, 파일 이름 및 fstream으로 작업 :

    • 가족 에게 인수를 전달 std::string하거나 const char*파일 이름을 지정 하지 마십시오 fstream. MSVC STL은 UTF-8 인수를 지원하지 않지만 비표준 확장명을 가지며 다음과 같이 사용해야합니다.
    • std::string로 다음 std::wstringUtils::Convert같이 인수를 변환하십시오 .

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |
                        std::ios_base::binary);
      

      MSVC의 태도가 fstream바뀔 때 변환을 수동으로 제거해야합니다 .

    • 이 코드는 다중 플랫폼이 아니며 나중에 수동으로 변경해야 할 수도 있습니다
    • 자세한 정보는 fstream유니 코드 리서치 / 토론 사례 4215를 참조하십시오.
    • 비 UTF8 컨텐츠로 텍스트 출력 파일을 생성하지 마십시오
    • fopen()RAII / OOD 이유로 사용하지 마십시오 . 필요한 경우 _wfopen()위의 WinAPI 규칙을 사용하십시오 .

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

// Interface to MFC
std::string convert(const CString &mfcString)
{
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
#else
    return mfcString.GetString();   // This branch is deprecated.
#endif
}

CString convert(const std::string &s)
{
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
#else
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
#endif
}

39
동의 할 수 없습니다. 많은 아시아 언어에서 utf8에 비해 utf16의 장점은 사용자가 만드는 요점을 완전히 지배합니다. 일본어, 태국어, 중국어 등 이이 인코딩을 포기하기를 바랍니다. 문자셋 사이의 문제 충돌은 차이점을 제외하고는 문자셋이 대부분 비슷해 보일 때입니다. 나는 표준화를 제안한다 : 고정 7 비트 : iso-irv-170; 8 비트 변수 : utf8; 16 비트 변수 : utf16; 32 비트 고정 : ucs4.

82
@Charles : 입력 해 주셔서 감사합니다. 사실, 일부 BMP ​​문자는 UTF-16보다 UTF-8이 더 깁니다. 그러나 문제는 BMP 한자에 걸리는 바이트 단위가 아니라 소프트웨어 설계의 복잡성이 발생한다는 점입니다. 중국 프로그래머가 가변 길이 문자를 디자인 해야하는 경우 UTF-8은 시스템의 다른 변수와 비교하여 여전히 저렴한 가격 인 것 같습니다. 공간이 매우 중요한 경우 UTF-16을 압축 알고리즘으로 사용할 수 있지만 LZ와 일치하지 않으며 LZ 또는 다른 일반 압축 후에도 크기와 엔트로피가 거의 동일합니다.

32
기본적으로 말하는 것은 기존 char * 프로그램과 호환되는 One 인코딩을 통해 제공되는 단순화이며 오늘날 가장 인기있는 것은 상상할 수 없다는 것입니다. 그것은 오래된 "일반 텍스트"시절과 거의 같습니다. 이름을 가진 파일을 열고 싶습니까? 어떤 종류의 유니 코드 등을 신경 쓰지 않아도됩니다. 개발자, 개발자는 UTF-16을 아주 특별한 성능의 극한의 최적화로 제한하여 약간의 성능이 몇 달의 작업에 가치가 있다고 제안합니다.

17
Linux는 UTF-8을 내부적으로 사용하기로 선택할 때 특별한 요구 사항이 있습니다. Unix와의 호환성. Windows는이를 필요로하지 않았으므로 개발자가 유니 코드를 구현할 때 텍스트를 처리하는 거의 모든 기능의 UCS-2 버전을 추가하고 멀티 바이트 버전을 UCS-2로 변환하고 다른 버전을 호출하게했습니다. 나중에 UCS-2를 UTF-16으로 대체합니다. 반면에 리눅스는 8 비트 인코딩을 유지했고, 따라서 UTF-8을 사용했습니다.
Mircea Chirea

34
@Pavel Radzivilovsky : BTW, "다른 모든 인코딩은 결국 죽을 것이라고 믿습니다. 여기에는 MS-Windows, Java, ICU, python이 선호하지 않는 방식으로 사용하지 않는 것이 포함됩니다." 그리고 "특히, 나는 C ++에 wchar_t를 추가하는 것은 실수라고 생각하고, 그래서 C ++ 황소에 유니 코드 추가입니다." 아주 순진하거나 매우 거만합니다. 그리고 이것은 집에서 리눅스로 코딩하고 UTF-8 문자에 만족하는 누군가에게서 온 것입니다. 솔직히 말하면 : 그것은 일어나지 않을 것 입니다.
paercebal

157

유니 코드 코드 포인트는 문자가 아닙니다! 때로는 글리프도 아닙니다 (시각적 형태).

몇 가지 예 :

  • "ⅲ"와 같은 로마 숫자 코드 포인트. "iii"처럼 보이는 단일 문자입니다.
  • "á"와 같은 악센트 문자는 단일 결합 문자 "\ u00e1"또는 문자 및 분리 분음 부호 "\ u0061 \ u0301"로 표시 될 수 있습니다.
  • 그리스어 소문자 시그마와 같은 문자는 단어 위치의 중간 ( "σ")과 끝 ( "ς")에 대해 서로 다른 형식을 갖지만 검색의 동의어로 간주되어야합니다.
  • 컨텍스트에 따라 시각적으로 표시되거나 표시되지 않을 수 있고 의미 검색을 위해 무시되는 유니 코드 임의 하이픈 U + 00AD.

유니 코드 편집 권한을 얻는 유일한 방법 은 전문가가 작성한 라이브러리사용 하거나 전문가가되어 직접 작성하는 것입니다. 코드 포인트를 세고 있다면 죄의 상태에 살고 있습니다.


19
이. 아주 많이 요 UTF-16은 문제를 일으킬 수 있지만 UTF-32를 사용하더라도 문제가 발생할 수 있습니다.
bcat

11
캐릭터는 무엇입니까? 코드 포인트를 문자로 정의하고 거의 괜찮을 수 있습니다. 사용자가 볼 수있는 글리프를 의미한다면 다른 것입니다.
tchrist

7
@tchrist 그 공간을 할당하는 것이 확실하지만 그 정의는 괜찮습니까? 별로. 결합 문자를 단독 문자 (즉, 삭제 또는 "첫 N 문자 취하기"조작)로 처리하면 이상하고 잘못된 동작이 발생합니다. 코드 포인트가 다른 코드 포인트와 결합 된 경우에만 의미가있는 경우 적절한 방식으로 자체적으로 처리 할 수 ​​없습니다.
Voo

6
@Pacerier, 이것은 파티에 늦었지만 그것에 대해 언급해야합니다. 일부 언어에는 분음 부호 조합이 매우 다양합니다 (베트남어, 즉 mđt đừ). 분음 부호 당 하나의 문자가 아닌 조합을 갖는 것이 매우 유용합니다.
asthasr

21
용어에 대한 작은 참고 사항 : 코드 포인트 유니 코드 문자에 해당합니다 . Daniel이 여기서 말하는 것은 사용자가 인식 한 문자입니다 . 이는 유니 코드 그래 핀 클러스터에
Christoph

54

사용할 UTFF (Unicode Transformation Form)에 대한 간단한 경험 규칙이 있습니다.-저장 및 통신을위한 utf-8-데이터 처리를위한 utf-16-사용하는 대부분의 플랫폼 API가 utf-32 인 경우 utf-32 (UNIX 세계에서 일반적)

오늘날 대부분의 시스템은 utf-16 (Windows, Mac OS, Java, .NET, ICU, Qt)을 사용합니다. 이 문서도 참조하십시오 : http://unicode.org/notes/tn12/

"유해한 UTF-16"으로 돌아가서, 나는 말할 것입니다.

대리자를 두려워하는 사람들 (유니 코드를 가변 길이 인코딩으로 변환한다고 생각하는 사람들)은 문자와 합자, 변형 선택자를 결합하여 문자와 유니 코드 코드 포인트 간의 매핑을 매우 복잡하게 만드는 다른 (더 큰) 복잡성을 이해하지 못합니다. , 제어 문자 등

http://www.siao2.com/2009/06/29/9800913.aspx 에서이 시리즈를 읽고 UTF-16이 쉬운 문제가되는 방법을보십시오.


26
UNIX 세계에서 UTF-32가 공통적 인 예를 추가하십시오!
maxschlepzig

48
아니요, 데이터 처리에 UTF-16을 사용하고 싶지 않습니다. 엉덩이가 아프다. UTF-8의 단점은 있지만 장점은 없습니다. UTF-8과 UTF-32는 이전에 이름이 UCS-2 인 Mrs UTF-16으로 알려진 악의적 인 핵보다 분명히 뛰어납니다.
tchrist

34
어제 Java 코어 문자열 클래스의 equalsIgnoreCase메소드 ( 문자열 클래스의 다른 클래스)에서 UTF-8 또는 UTF-32 중 하나를 사용한 적이 없었던 버그를 발견했습니다 . UTF-16을 사용하는 코드에는 수백만 개의 수면 폭탄이 있으며, 나는 아프고 피곤합니다. UTF-16은 악의적 인 수두로 소프트웨어에 영원한 버그가 있습니다. 그것은 분명히 해롭고 더 이상 사용되지 않으며 금지되어야합니다.
tchrist

7
@tchrist 대리 인식 기능이 없기 때문에 (아무것도 없었을 때 작성되었고 슬프게 문서화되어 적응이 불가능한 방식으로 문서화되었으므로 .toUpperCase (char) 지정) 잘못된 동작이 발생합니까? 오래된 코드 포인트 맵을 가진 UTF-32 함수는 이것을 더 잘 처리하지 못한다는 것을 알고 있습니까? 또한 전체 Java API는 특히 대리자를 잘 처리하지 않으며 유니 코드에 대한 복잡한 점을 전혀 다루지 않습니다. 나중에 사용되는 인코딩은 전혀 중요하지 않습니다.
Voo

8
-1 : .Substring(1).NET 의 무조건 은 BMP가 아닌 유니 코드를 모두 지원하지 않는 간단한 예입니다. UTF-16을 사용하는 모든 것에는이 문제가 있습니다. 고정 너비 인코딩으로 취급하기가 너무 쉽고 문제가 너무 드물게 나타납니다. 따라서 유니 코드를 지원하려는 경우 적극적으로 유해한 인코딩이됩니다.
Roman Starkov

43

네 그럼요.

왜? 그것은 코드 운동과 관련이 있습니다 .

Tom Christiansen 의 대규모 코퍼스 에서 이러한 코드 포인트 사용 통계 를 보면 BMP가 아닌 코드 포인트보다 큰 경우 8 비트 트랜스 BMP 코드 포인트가 몇 가지 순서로 사용됩니다.

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE

 544 U+01D49E ‹𝒞›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL C
 450 U+01D4AF ‹𝒯›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL T
 385 U+01D4AE ‹𝒮›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL S
 292 U+01D49F ‹𝒟›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL D
 285 U+01D4B3 ‹𝒳›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL X

TDD dictum : "테스트되지 않은 코드는 코드가 손상되었습니다"를 받아 "실행되지 않은 코드는 코드가 손상되었습니다"로 바꾸고 프로그래머가 BMP가 아닌 코드 포인트를 처리하는 빈도를 생각하십시오.

가변 너비 인코딩으로 UTF-16을 처리하지 않는 것과 관련된 버그는 UTF-8의 해당 버그보다 훨씬 눈에 띄지 않을 수 있습니다. 일부 프로그래밍 언어는 여전히 UCS-2 대신 UTF-16을 제공한다고 보장하지 않으며 일부 고급 프로그래밍 언어는 코드 포인트 대신 코드 단위에 대한 액세스를 제공합니다 (C조차도 wchar_t일부 플랫폼의 기능에 관계없이 를 사용하는 경우 코드 포인트 ).


16
"가변 폭 인코딩으로서 UTF-16을 다루지 않는 것과 관련된 버그는 UTF-8의 동등한 버그보다 눈에 띄지 않을 가능성이 높습니다." 이것이 문제의 핵심이므로 정답입니다.
Sean McMillan

3
정확하게. UTF-8 처리가 중단 된 경우 즉시 알 수 있습니다. UTF-8 처리가 중단 된 경우, 드문 Han 문자 나 수학 기호를 입력 한 경우에만 알 수 있습니다.
기계 달팽이

1
매우 사실이지만, 반면에 덜 빈번한 경우에 버그를 찾기 위해 운에 의존해야하는 경우에 대한 단위 테스트는 무엇입니까?
musiphil

@musiphil : 그렇다면 BMP 이외의 문자에 대한 단위 테스트를 마지막으로 작성한 시간은 언제입니까?
ninjalj 2016 년

1
내 이전 진술을 자세히 설명하려면 UTF-8을 사용하더라도 몇 가지 실제 예제를 본 후에 모든 사례를 다룰 수는 없습니다. UTF-16과 동일 : 코드가 서로 게이트되지 않은 코드와 서로 게이트로 작동하는지 테스트해야합니다. (누군가는 UTF-8에 4 개 이상의 주요 사례가 있고 UTF-16에 2 개만 있다고 주장 할 수도 있습니다.)
musiphil

40

UTF-16을 해로운 것으로 생각하면 unicode에 대해 더 많이 이해해야 한다고 말합니다 .

주관적인 질문에 대한 나의 의견을 표명 한 것에 대해 공감 당 했으므로 자세히 설명하겠습니다. UTF-16에 대해 귀찮게하는 것이 정확히 무엇입니까? 모든 것이 UTF-8로 인코딩 된 것을 선호합니까? UTF-7? 아니면 UCS-4는 어떻습니까? 물론 특정 응용 프로그램은 모든 문자 코드를 처리하도록 설계되지는 않았지만 특히 오늘날의 글로벌 정보 도메인에서 국제 경계 간 통신에 필요합니다.

그러나 실제로 UTF-16이 혼란 스럽거나 부적절하게 구현 될 수 있기 때문에 (유니 코드가 확실 할 수 있음) 유해한 것으로 간주되는 경우, 어떤 문자 인코딩 방법이 무해한 것으로 간주됩니까?

편집 : 명확하게 : 왜 표준의 부적절한 구현이 표준 자체의 품질을 반영한다고 생각합니까? 다른 사람들이 나중에 지적했듯이, 응용 프로그램이 도구를 부적절하게 사용한다고해서 도구 자체에 결함이있는 것은 아닙니다. 이 경우 "var 키워드가 유해한 것으로 간주 됨"또는 "스레딩이 유해한 것으로 간주 됨"과 같은 것을 말할 수 있습니다. 저는이 질문이 표준의 품질과 본질을 많은 프로그래머들이 표준을 올바르게 구현하고 사용하는 데 어려움을 겪고 있다고 생각합니다. 이는 유니 코드 자체가 아닌 유니 코드의 작동 방식에 대한 이해 부족에서 비롯된 것입니다.


33
-1 : Artyom의 일부 이의 제기를 단순히 후원하는 것이 아니라 해결하는 것은 어떻습니까?

8
BTW :이 기사를 쓰기 시작했을 때 나는 실수 가 많기 때문에 "유니 코드의 Softeare 기사에 Joel이 유해한 것으로 간주해야합니까?"라고 쓰고 싶었습니다 . 예를 들어 : utf-8 인코딩은 6이 아닌 최대 4자를 사용합니다. 또한 실제로 다른 UCS-2와 UTF-16을 구분하지 않으며 실제로 문제를 일으 킵니다.

32
또한 Joel이 해당 기사를 작성할 때 UTF-8 표준은 6 바이트가 아니라 4 바이트가 아니 었습니다. RFC 3629는 기사를 작성한 후 몇 개월 동안 표준을 4 바이트로 변경했습니다. 인터넷의 다른 모든 것들과 마찬가지로, 둘 이상의 소스에서 읽고 소스의 나이를 알고 있어야합니다. 이 링크는 "모두 끝"이 아니라 시작점입니다.

7
나는 거의 모든 경우에 가변 길이 인코딩 (BMP 포함) 또는 고정 길이 인코딩 인 utf-8 또는 utf-32를 찍을 것입니다.

18
@ iconiK : 바보하지 마십시오. UTF-16은 텍스트 처리를위한 사실상의 표준이 아닙니다 . Perl이 텍스트 처리에 더 적합한 프로그래밍 언어를 보여주십시오. Perl은 항상 (10 년 이상) 내부적으로 UTF-8 표현을 가진 추상 문자를 사용했습니다. 이로 인해 모든 Perl 프로그램은 사용자가 이디 오틱 대리 물로 끊임없이 원숭이를 돌릴 필요없이 모든 유니 코드를 자동으로 처리합니다. 문자열의 길이는 코드 단위가 아니라 코드 포인트 수입니다. 다른 것은 거꾸로 호환성을 위해 어리석은 바보입니다.
tchrist

37

Utf-16 인코딩에는 아무런 문제가 없습니다. 그러나 16 비트 단위를 문자로 취급하는 언어는 제대로 설계되지 않은 것으로 간주해야합니다. char항상 문자를 나타내는 것은 아닌 ' ' 라는 유형의 유형을 갖는 것은 상당히 혼란 스럽습니다. 대부분의 개발자는 문자 유형이 코드 포인트 또는 문자를 나타낼 것으로 예상하기 때문에 BMP (Byound BMP) 문자에 노출되면 많은 코드가 중단 될 수 있습니다.

그러나 utf-32를 사용한다고해서 각 32 비트 코드 포인트가 항상 문자를 나타내는 것은 아닙니다. 문자 결합으로 인해 실제 문자는 여러 코드 포인트로 구성 될 수 있습니다. 유니 코드는 결코 사소하지 않습니다.

BTW. Utf-8이 제공되는 문자가 8 비트가 될 것으로 예상되는 플랫폼 및 응용 프로그램에는 동일한 종류의 버그가있을 수 있습니다.


12
Java의 경우 타임 라인 ( java.com/en/javahistory/timeline.jsp )을 보면 유니 코드가 16 비트 (1996 년에 변경됨) 동안 주로 String 개발이 발생했음을 알 수 있습니다. 그들은 BMP가 아닌 코드 포인트를 처리하는 능력을 강화해야했기 때문에 혼란을 겪었습니다.
캐시 반 스톤

10
@Kathy : C #에 대한 변명은 아닙니다. 일반적으로 CodePoint단일 코드 포인트 (21 비트)를 CodeUnit보유하는 유형, 단일 코드 단위 (UTF-16의 경우 16 비트)를 보유하는 Character유형이 있어야 하며 유형은 이상적으로 완전한 grapheme을 지원 해야한다는 데 동의합니다 . 그러나 그것은 기능적으로 그것과 같습니다 String...
Joey

1
이 답변은 거의 두 살이지만, 나는 그것에 대해 의견을 말할 수는 없습니다. "항상 캐릭터를 나타내는 것이 아닌 'char'라는 유형을 갖는 것은 상당히 혼란 스럽다." 그러나 사람들은 C 등에서 항상 사용하여 단일 바이트에 저장할 수있는 정수 데이터를 나타냅니다.
JAB

그리고 문자 인코딩을 올바르게 처리하지 못하는 많은 C 코드를 보았습니다 .
dan04

1
C #은 다른 변명을 가지고 있습니다 : Windows 용으로 설계되었으며 Windows는 UCS-2를 기반으로 구축되었습니다 (오늘날조차 Windows API가 UTF-8을 지원할 수 없다는 것은 매우 짜증납니다). 또한 Microsoft는 Java 호환성을 원한다고 생각합니다 (.NET 1.0에는 Java 호환성 라이브러리가 있었지만 Java 지원은 매우 빠르게 중단되었습니다. Sun에 대한 MS의 소송 때문일까요?)
Qwertie

20

개인적으로 선택하는 것은 항상 UTF-8을 사용하는 것입니다. 거의 모든 것에 대한 Linux의 표준입니다. 많은 레거시 앱과 호환됩니다. 비 라틴 문자에 사용되는 여분의 공간은 다른 UTF 형식에 비해 매우 적은 오버 헤드가 있으며 라틴 문자에 대한 공간이 크게 절약됩니다. 웹상에서 라틴어는 최고가 될 것입니다. 그리고 원래 게시물의 주요 주장 중 하나를 해결하기 위해 거의 모든 프로그래머는 UTF-8에 때때로 멀티 바이트 문자가 있음을 알고 있습니다. 모든 사람이 이것을 올바르게 다루지는 않지만 UTF-16에 대해 말할 수있는 것 이상을 일반적으로 알고 있습니다. 그러나 물론 응용 프로그램에 가장 적합한 것을 선택해야합니다. 그렇기 때문에 처음에는 둘 이상이 있습니다.


3
UTF-16은 BMP 내부의 모든 것에 대해 더 간단하므로 널리 사용됩니다. 그러나 나는 UTF-8의 팬이기도하며 바이트 순서에도 문제가 없으므로 이점이 있습니다.
Malcolm

2
이론적으로는 그렇습니다. 실제로 UTF-16BE와 같은 것들이 있는데 BOM이없는 빅 엔디안의 UTF-16을 의미합니다. 이것은 내가 만든 것이 아니며, ID3v2.4 태그에서 허용되는 실제 인코딩입니다 (ID3v2 태그는 빨라지지만 불행히도 널리 사용됩니다). 이러한 경우 텍스트 자체에는 BOM이 없으므로 엔디안을 외부 적으로 정의해야합니다. UTF-8은 항상 한 가지 방법으로 작성되며 그러한 문제는 없습니다.
Malcolm

23
아니요, UTF-16은 더 간단하지 않습니다. 더 어렵다. 너비가 고정되어 있다고 오해하고 속입니다. 너무 늦을 때까지 알지 못하기 때문에 그러한 코드는 모두 깨졌습니다. CASE IN POINT : 어제 Java Core 라이브러리에서 또 다른 어리석은 UTF-16 버그를 발견했습니다. 이번에는 String.equalsIgnoreCase가 UCS-2 braindeath buggery에 남아 16/17 유효한 유니 코드 코드 포인트에서 실패했습니다. 그 코드는 얼마나 오래 있었습니까? 버그가 있다는 변명은 없습니다. UTF-16은 멍청한 사고와 사고가 일어나기를 기다립니다. UTF-16에서 비명을 지르십시오.
tchrist

3
@tchrist UTF-16의 길이가 고정되어 있지 않다는 것을 모르기 위해서는 무식한 개발자 여야합니다. Wikipedia로 시작하면 맨 위에서 다음을 읽습니다. "코드 포인트 당 하나 또는 두 개의 16 비트 코드 단위의 가변 길이 결과를 생성합니다." 유니 코드 FAQ에는 unicode.org/faq//utf_bom.html#utf16-1이 있습니다. 나는 UTF-16이 가변 길이라는 곳 어디에서나 쓰면 어떻게 사람을 속일 수 있는지 모른다. 이 방법은 UTF-16 용으로 설계되지 않았으므로 단순한 것으로 유니 코드로 간주해서는 안됩니다.
Malcolm

2
@tchrist 통계에 대한 출처가 있습니까? 좋은 프로그래머가 부족한 경우, 우리는 더 가치가 있기 때문에 이것이 좋다고 생각합니다. :) Java API의 경우 char 기반 파트는 결국 사용되지 않을 수 있지만 이것이 사용되지 않을 것이라는 보장은 없습니다. 호환성 문제로 인해 제거되지는 않습니다.
Malcolm

18

고정 크기 기호를 사용하는 인코딩이 있습니다. 확실히 UTF-32를 의미합니다. 그러나 각 심볼 당 4 바이트는 너무 많은 공간을 낭비하는데 왜 일상적인 상황에서 사용합니까?

내 생각에, 대부분의 문제는 일부 소프트웨어가 유니 코드 표준에 뒤떨어졌지만 상황을 신속하게 시정하지 않았다는 사실에서 나타납니다. Opera, Windows, Python, Qt-UTF-16이 널리 알려 지거나 존재하기 전에 나타났습니다. 그러나 Opera, Windows 탐색기 및 메모장에서는 더 이상 BMP 외부의 문자 (더 이상 내 PC에서는)에 문제가 없음을 확인할 수 있습니다. 그러나 어쨌든 프로그램이 서로 게이트 쌍을 인식하지 못하면 UTF-16을 사용하지 않습니다. 이러한 프로그램을 처리 할 때 어떤 문제가 발생하더라도 UTF-16 자체와는 아무런 관련이 없습니다.

그러나 BMP 만 지원하는 레거시 소프트웨어의 문제는 다소 과장된 것 같습니다. BMP 외부의 문자는 매우 특정한 경우와 영역에서만 발생합니다. 유니 코드 공식 FAQ 에 따르면 , "동아시아 텍스트에서도 대리 쌍의 발생률은 평균적으로 모든 텍스트 스토리지의 1 % 미만이어야합니다". 물론 프로그램이 유니 코드를 준수하지 않기 때문에 BMP 외부의 문자 는 무시해서는 안되지만 대부분의 프로그램은 이러한 문자가 포함 된 텍스트를 다루기위한 것이 아닙니다. 그것이 그들이 그것을 지원하지 않으면 불쾌하지만 재앙이 아닌 이유입니다.

이제 대안을 고려해 봅시다. UTF-16이 존재하지 않으면 비 ASCII 텍스트에 적합한 인코딩이없고 UCS-2 용으로 작성된 모든 소프트웨어는 유니 코드 호환을 유지하도록 완전히 재 설계되어야합니다. 후자는 아마도 유니 코드 채택 속도를 늦출 것입니다. 또한 UTF-8이 ASCII와 관련하여 UCS-2에서 텍스트와의 호환성을 유지할 수 없었습니다.

이제 모든 레거시 문제를 제외하고 인코딩 자체에 대한 논쟁은 무엇입니까? 나는 오늘날 개발자들이 UTF-16이 가변 길이라는 것을 알지 못한다는 것을 의심합니다. 누군가가 가능한 문제로 복잡성을 지적했다면 UTF-16은 UTF-8보다 구문 분석하기가 훨씬 어렵습니다. 또한 UTF-16에서만 문자열 길이를 결정하는 것이 엉망이라고 생각하는 것은 잘못입니다. UTF-8 또는 UTF-32를 사용하는 경우 하나의 유니 코드 코드 포인트가 반드시 하나의 문자를 의미하지는 않습니다. 그 외에는 인코딩에 대해 실질적인 것이 없다고 생각합니다.

따라서 인코딩 자체가 유해하다고 생각하지 않습니다. UTF-16은 단순성과 컴팩트 함의 절충안 이며 필요한 곳에서 필요한 것을 사용하는 데 아무런 해 가 없습니다 . 경우에 따라 ASCII와의 호환성을 유지하고 UTF-8이 필요한 경우가 있습니다. 어떤 경우에는 한 표의 문자로 작업하고 UTF-16을 사용하여 공간을 절약하려는 경우가 있습니다. 길이 인코딩. 더 적절한 것을 사용하고 올바르게 수행하십시오.


21
그것은 다소 깜박 거리는 앵글로 중심의 관점 인 Malcolm입니다. 거의 "ASCII는 미국에 충분합니다-세계의 나머지는 우리와 함께해야합니다."
Jonathan Leffler 2016 년

28
실제로 나는 러시아 출신이며 (자신의 프로그램을 포함하여) 항상 키릴 릭을 경험하기 때문에 앵글로 중심의 견해를 가지고 있다고 생각하지 않습니다. :) ASCII를 언급하는 것은 유니 코드가 아니며 특정 문자를 지원하지 않기 때문에 적절하지 않습니다. UTF-8, UTF-16, UTF-32는 매우 동일한 국제 문자 세트를 지원하며 특정 영역에서 사용하기위한 것입니다. 그리고 이것은 정확히 내 요점입니다. 대부분 영어를 사용하는 경우 UTF-8을 사용하고, 대부분 키릴 문자를 사용하는 경우 UTF-16을 사용하고, 고대 언어를 사용하는 경우 UTF-32를 사용하십시오. 아주 간단합니다.
Malcolm

16
"일본어, 중국어 또는 아랍어와 같은 아시아 스크립트도 BMP에 속합니다. BMP 자체는 실제로 매우 크며 현재 사용되는 모든 스크립트를 포함 할만큼 충분히 큽니다."이것은 모두 잘못되었습니다. BMP는 0xFFFF 문자 (65536)를 포함합니다. 중국만으로는 그 이상이 있습니다. 중국 표준 (GB 18030)은 그 이상입니다. 유니 코드 5.1은 이미 100,000 개 이상의 문자를 할당했습니다.

12
@Marcolm : "BMP 자체는 실제로 매우 커서 현재 사용되는 모든 스크립트를 포함 할만큼 충분히 큽니다."사실이 아닙니다. 이 시점에서 유니 코드는 이미 BMP보다 많은 약 100K 문자를 할당했습니다. BMP 외부에는 한자 덩어리가 있습니다. 그리고 그중 일부는 GB-18030 (필수 중국어 표준)에 필요합니다. 다른 것들은 (필수) 일본 및 한국 표준에 의해 요구됩니다. 따라서 해당 시장에서 무언가를 판매하려고하면 BMP 지원 이상이 필요합니다.

8
UTF-16을 사용하지만 좁은 BMP 문자 만 처리 할 수있는 것은 실제로 UTF-16을 사용하지 않습니다. 버그가 있고 고장입니다. OP의 전제는 전제입니다. UTF-16은 순진한 사람들이 깨진 코드를 작성하도록 유도하기 때문에 유해합니다. 유니 코드 텍스트를 처리하거나 처리 할 수 ​​없습니다. 당신이 할 수 없다면, 당신은 ASCII 전용 텍스트 처리만큼 바보 같은 부분 집합을 선택하는 것입니다.
tchrist

16

수년간의 Windows 국제화 작업은 특히 동아시아 언어에서 작동했을 수 있지만, 프로그램 내부에서 문자열을 표현하려면 UTF-16, 일반 텍스트와 같은 문서의 네트워크 또는 파일 저장에는 UTF-8을 사용합니다. UTF-16은 일반적으로 Windows에서 더 빠르게 처리 될 수 있으므로 Windows에서 UTF-16을 사용하는 것이 가장 큰 이점입니다.

UTF-16으로의 도약으로 국제 텍스트를 처리하는 일반 제품의 적절성이 크게 향상되었습니다. 대리 쌍을 고려해야 할 경우 (기본적으로 삭제, 삽입 및 줄 바꿈)가 필요한 경우는 극히 드물며 평균 사례는 대부분 직선입니다. 또한 JIS 변형과 같은 이전 인코딩과 달리 UTF-16은 서로 게이트 쌍을 매우 좁은 범위로 제한하므로 검사가 실제로 빠르고 앞뒤로 작동합니다.

물론, 올바르게 인코딩 된 UTF-8에서도 거의 빠릅니다. 그러나 대리 쌍을 두 개의 UTF-8 시퀀스로 잘못 인코딩하는 손상된 UTF-8 응용 프로그램도 많이 있습니다. 따라서 UTF-8은 구원을 보장하지 않습니다.

IE는 일반적으로 UTF-8 페이지에서 내부 UTF-16 표현으로 변환하더라도 2000 년 이후부터 대리 쌍을 합리적으로 잘 처리합니다. 파이어 폭스에서도 제대로 작동한다고 확신하므로 Opera가하는 일에 관심이 없습니다.

UTF-32 (일명 UCS4)는 공간이 많이 필요하기 때문에 대부분의 응용 프로그램에서 무의미합니다. 따라서 스타터가 아닙니다.


6
UTF-8 및 대리 쌍에 대한 귀하의 의견을 얻지 못했습니다. 대리 쌍은 UTF-16 인코딩에서 의미있는 개념 일뿐입니다. 아마도 UTF-16 인코딩에서 UTF-8 인코딩으로 직접 변환하는 코드는 이것이 잘못 될 수 있으며,이 경우 UTF-8을 쓰지 않고 UTF-16을 잘못 읽는 것이 문제입니다. 맞습니까?
Craig McQueen

11
Jason이 이야기하는 것은 의도적으로 UTF-8을 이런 식으로 구현하는 소프트웨어입니다. 서로 게이트 쌍을 만든 다음 UTF-8을 각각 절반으로 인코딩합니다. 해당 인코딩의 올바른 이름은 CESU-8이지만 Oracle (예 : Oracle)은이를 UTF-8로 잘못 표시합니다. Java는 객체 직렬화를 위해 유사한 체계를 사용하지만 내부적으로 만 "수정 된 UTF-8"로 문서화되어 있습니다. (이제 사람들이 그 문서를 읽고 DataInputStream # readUTF () 및 DataOutputStream # writeUTF ()를 부적절하게 사용하지 못하게 할 수 있다면 ...

AFAIK, UTF-32는 여전히 가변 길이 인코딩이며 특정 코드 포인트 범위 인 UCS4와 동일하지 않습니다.
Eonil

@Uonil, UTF-32는 UCS5 이상과 같은 기능을 가진 유니 코드 표준이있는 경우에만 UCS4와 구별 될 수 있습니다.
JasonTrue

@JasonTrue 그럼에도 불구하고 결과는 우연히 동일하지만 디자인에 의해 보장되지는 않습니다. 32 비트 메모리 어드레싱, Y2K, UTF16 / UCS2에서도 같은 일이 발생했습니다. 아니면 그 평등을 보장 할 수 있습니까? 우리가 있다면 기꺼이 사용하겠습니다. 그러나 가능한 깨지기 쉬운 코드 를 작성하고 싶지 않습니다 . 문자 수준 코드를 작성 중이며 UTF <-> 코드 포인트 사이에서 코드 변환하는 보장 방법이 부족하여 많은 버그가 있습니다.
Eonil

16

UTF-8은 확실한 방법이며, 고성능 랜덤 액세스가 필요한 알고리즘에서 내부 사용을 위해 UTF-32를 사용할 수 있습니다 (그러나 문자 결합은 무시합니다).

UTF-16 및 UTF-32 (및 LE / BE 변형) 모두 엔디안 문제가 있으므로 외부에서 사용해서는 안됩니다.


9
UTF-8에서도 일정한 시간 랜덤 액세스가 가능하며 코드 포인트 대신 코드 단위 만 사용하십시오. 어쩌면 실제 임의 코드 포인트 액세스가 필요하지만 유스 케이스를 본 적이 없으며 무작위 grapheme 클러스터 액세스를 원할 것입니다.

15

UTF-16? 확실히 해 롭습니다. 여기에 내 소금 알갱이가 있지만 프로그램에는 텍스트에 대해 정확히 세 가지 인코딩이 허용됩니다.

  • ASCII : 더 나은 것을 감당할 수없는 저수준의 물건 (예 : 마이크로 컨트롤러)을 다룰 때
  • UTF8 : 파일과 같은 고정 너비 미디어에 저장
  • 정수 코드 포인트 ( "CP"?) : 프로그래밍 언어 및 플랫폼에 편리한 가장 큰 정수의 배열입니다 (낮은 해상도의 한계에서 ASCII로 감소). 구형 컴퓨터의 경우 int32이고 64 비트 주소 지정이있는 모든 컴퓨터의 경우 int64 여야합니다.

  • 분명히 레거시 코드에 대한 인터페이스는 이전 코드가 올바르게 작동하기 위해 필요한 인코딩을 사용합니다.


4
@ simon buchan, U+10ffffmax는 코드 포인트가 부족하면 창 밖으로 나갑니다. 즉, 속도를 위해 p64 시스템에서 int32를 사용하는 것이 안전 할 것입니다. U+ffffffff2050 년경에 128 비트 시스템에 대한 코드를 다시 작성하기 전에 초과 할 가능성이 의심 되기 때문 입니다. "가장 큰"(대부분 int256 또는 bignums 또는 다른 것)와는 달리 편리합니다. "
David X

1
@David : 유니 코드 5.2는 107,361 개의 코드 포인트를 인코딩합니다. 사용되지 않는 코드 포인트는 867,169 개입니다. "언제"는 바보입니다. 유니 코드 코드 포인트는 UTF-16이 의존하는 속성 인 0에서 0x10FFFF까지의 숫자로 정의 됩니다. (또한 2050은 64 비트 시스템이 주소 공간에서 인터넷 전체를 보유 할 수있을 때 128 비트 시스템에 대한 추정치를 크게 낮추는 것 같습니다.)

3
@David : 당신의 "언제"는 128 비트 스위치가 아니라 유니 코드 코드 포인트가 부족하다는 것을 의미합니다. 예, 몇 세기 안에있을 것입니다. 메모리와 달리 문자의 기하 급수적 인 증가는 없으므로 유니 코드 컨소시엄은 특히 위의 코드 포인트를 할당 하지 않도록 보장했습니다 U+10FFFF. 이것은 실제로 21 비트 이면 누구에게나 충분한 상황 중 하나입니다 .

10
@Simon Buchan : 적어도 첫 접촉까지. :)

3
유니 코드는 U + FFFF 이상의 코드 포인트도 없음을 보장하는 데 사용됩니다.
Shannon Severance

13

유니 코드 는 최대 0x10FFFF (1,114,112 코드)까지 코드 포인트를 정의하며, 문자열 / 파일 이름 등을 다루는 다국어 환경에서 실행되는 모든 응용 프로그램은이를 올바르게 처리해야합니다.

Utf-16 : 1,112,064 코드 만 포함합니다. 유니 코드 끝의 것은 15-16면 (개인 사용 영역)에서 온 것이지만 Utf-16 개념을 깨는 것을 제외하고는 앞으로 더 이상 성장할 수 없습니다 .

Utf-8 : 이론적으로 2,216,757,376 코드를 다룹니다. 유니 코드 코드 의 현재 범위는 최대 4 바이트 시퀀스로 표시 될 수 있습니다. 바이트 순서 문제 가 없으며 ascii와 "호환"됩니다.

Utf-32 : 이론적으로 2 ^ 32 = 4,294,967,296 코드를 다룹니다. 현재는 가변 길이로 인코딩되지 않았으며 앞으로는 없을 것입니다.

이러한 사실은 자명하다. Utf-16 의 일반적인 사용을 주장하는 것을 이해하지 못합니다 . 가변 길이 인코딩 (인덱스로 액세스 할 수 없음), 현재에도 전체 유니 코드 범위 를 다루는 데 문제가 있으며 바이트 순서를 처리해야합니다. 다른 장소들. 다중 플랫폼 코드를 작성할 때 Utf-8을 기본적으로 사용하고 플랫폼에 따라 엔드 포인트에서만 변환하는 것이 좋습니다 (이미 제안한 바와 같이). 인덱스를 통한 직접 액세스가 필요하고 메모리에 문제가없는 경우 Utf-32를 사용해야합니다.

주요 문제는 Windows Unicode = Utf-16을 다루는 많은 프로그래머 가 가변 길이 인코딩이라는 사실을 알거나 무시하지 못한다는 것입니다.

그것이 일반적으로 * nix 플랫폼에있는 방식은 꽤 훌륭합니다 .c 문자열 (char *)은 Utf-8 인코딩 으로 해석되고 넓은 c 문자열 (wchar_t *)은 Utf-32 로 해석됩니다 .


7
참고 : UTF-16은 유니 코드 컨소시엄이 10FFFF가 유니 코드의 최상위 범위이고 정의 된 UTF-8 최대 4 바이트 길이이고 명시 적으로 제외 된 범위 0xD800-0xDFFF를 유효한 코드 포인트 범위에서 제외하고이 범위는 대리 쌍. 따라서 모든 유효한 유니 코드 텍스트는 이러한 인코딩 중 하나로 각각 표시 될 수 있습니다. 미래로의 성장에 대해서도. 백만 장의 코드 포인트가 먼 미래에 충분하지 않은 것 같습니다.

7
@Kerrek : 잘못된 정보 : UCS-2는 유효한 유니 코드 인코딩이 아닙니다. 정의에 따른 모든 UTF- * 인코딩은 교환에 적합한 모든 유니 코드 코드 포인트를 나타낼 수 있습니다. UCS-2는 그보다 훨씬 적은 수를 더할 수 있습니다. 반복 : UCS-2는 유효한 유니 코드 인코딩이 아니며 ASCII보다 더 중요합니다.
tchrist

1
" Utf-8 의 일반적인 사용을 옹호하는 것을 이해하지 못합니다 . 가변 길이 인코딩 (인덱스로 액세스 할 수 없음)"
Ian Boyd

9
@Ian Boyd, 임의 접근 패턴으로 문자열의 개별 문자에 접근 할 필요성은 엄청나게 과장되어 있습니다. 문자 행렬의 대각선을 계산하는 것만큼이나 일반적입니다. 문자열은 사실상 항상 순차적으로 처리 되며 UTF-8 문자 N에 있다고 가정 할 때 UTF-8 문자 N + 1에 액세스하면 문제가 없습니다. 문자열에 무작위로 액세스 할 필요가 거의 없습니다. UTF-8 대신 UTF-32로 이동하는 것이 스토리지 공간의 가치가 있다고 생각하든, 여러분 자신의 의견이지만, 그것은 전혀 문제가 아닙니다.
tchrist

2
@tchrist, 역순 반복을 "순차"로 포함하면 문자열이 거의 항상 순차적으로 처리되고 문자열의 끝 부분을 알려진 문자열과 조금 더 비교할 수 있습니다. 두 가지 매우 일반적인 시나리오는 문자열 끝에서 공백을 자르고 경로 끝에서 파일 확장자를 확인하는 것입니다.
Andy Dent

11

이것을 목록에 추가하십시오.

제시된 시나리오는 간단합니다 (원래보다 여기에 제시 할 때 더 간단합니다!). 1. WinForms TextBox는 비어있는 Form에 있습니다. MaxLength는 20으로 설정되어 있습니다.

2. 사용자가 텍스트 상자에 입력하거나 텍스트를 붙여 넣을 수 있습니다.

3. TextBox에 입력하거나 붙여 넣은 내용에 관계없이 20으로 제한되지만 20을 넘어 서면 텍스트가 비프 음으로 울립니다 (여기서 YMMV; 나는 그 효과를 내기 위해 사운드 구성을 변경했습니다!).

4. 작은 텍스트 패킷이 흥미 진진한 모험을 시작하기 위해 다른 곳으로 보내집니다.

이제 이것은 쉬운 시나리오이며, 여가 시간에 누구나 쓸 수 있습니다. 방금 지루하고 전에 시도한 적이 없기 때문에 WinForms를 사용하여 여러 프로그래밍 언어로 직접 작성했습니다. 그리고 여러 실제 언어로 된 텍스트를 사용하면 전 세계의 다른 사람들보다 키보드 레이아웃이 더 많기 때문에 유선으로 연결됩니다.

나는 지루함을 개선하는 데 도움을주기 위해 Magic Carpet Ride 라는 이름을 지었다 .

이것은 가치가있는 것으로 작동하지 않았습니다.

대신 매직 카펫 라이드 폼에 다음 20 자를 입력했습니다 .

0123401234012340123 𠀀

어 오.

마지막 문자는 U + 20000이며, 유니 코드의 첫 번째 확장 B 표의 문자입니다 (일명 U + d840 U + dc00).

여기에 이미지 설명을 입력하십시오

그리고 지금 우리는 볼 게임이 있습니다.

TextBox.MaxLength가 이야기 할 때

텍스트 상자에 수동으로 입력 할 수있는 최대 문자 수를 가져 오거나 설정합니다.

그것이 실제로 의미하는 것은

텍스트 상자에 수동으로 입력 할 수있는 UTF-16 LE 코드 단위의 최대 수를 가져 오거나 설정하고 다른 사람에게만 집착하는 언어 적 문자 개념으로 cutesy 게임을 시도하는 문자열에서 살아있는 쓰레기를 무자비하게 잘라냅니다. 카플란 동료가 불쾌감을 줄 것입니다 (더 많은 것을 꺼내야합니다!).

나는 시도하고 문서가 .... 업데이트 것에 대해 볼 수 있습니다
내 기억 정기 독자 UTF-16에 UCS-2 시리즈의 단순한 개념 내 불행주의 할 것이다 TextBox.MaxLength을 그리고 최소한이 경우에 처리하는 방법 드라코 니안 동작이 잘못된 시퀀스를 생성하는 경우, .Net Framework의 다른 부분에서

  • System.Text.EncoderFallbackException : 인덱스 0에서 유니 코드 문자 \ uD850을 지정된 코드 페이지로 변환 할 수 없습니다. *

내 동료 Dan Thompson 이하 고있는 것처럼 .Net Framework의 다른 곳 에서이 문자열을 전달하면 예외입니다.

이제 전체 UCS-2에서 UTF-16 시리즈 까지 많은 사람들이 접근 할 수 없을 것입니다.
그러나 TextBox.Text가 System.String을 생성하지 않을 것으로 기대하는 것이 합리적이지 않습니다. .Net Framework의 다른 부분이 발생하지 않습니까? 내 말은, 컨트롤에 어떤 이벤트 형태의 기회가있어서 다가오는 잘림에 대해 더 똑똑한 유효성 검사-컨트롤 자체가 신경 쓰지 않는 유효성 검사를 쉽게 추가 할 수있는 위치를 알려줍니다. 나는이 펑크 컨트롤이 예기치 않은 예외를 발생시켜 응용 프로그램을 조잡한 서비스 거부로 종료하도록 클래스 화 할 수 있다면 보안 문제를 일으킬 수있는 안전 계약을 위반하고 있다고 말할 것입니다. 왜 WinForms 프로세스, 방법 또는 알고리즘 또는 기술이 유효하지 않은 결과를 생성해야합니까?

출처 : Michael S. Kaplan MSDN 블로그


고마워요, 아주 좋은 링크! 질문의 문제 목록에 추가했습니다.

9

UTF-16이 유해하다고 반드시 말할 필요는 없습니다. 우아하지는 않지만 GB18030은 GB2312와 UTF-8은 ASCII와 마찬가지로 UCS-2와의 하위 호환성을 제공합니다.

그러나 Microsoft와 Sun이 약 16 비트 문자로 거대한 API를 구축 한 후 미드 스트림에서 유니 코드 구조를 근본적으로 변경하는 것은 해로 웠습니다. 변화에 대한 인식을 확산시키지 못한 것은 더욱 해 롭습니다.


8
UTF-8은 ASCII의 상위 집합이지만 UTF-16은 UCS-2의 상위 집합이 아닙니다. 거의 수퍼 세트이지만 UCS-2를 UTF-8로 올바르게 인코딩하면 CESU-8로 알려진 혐오가 발생합니다. UCS-2에는 대체 코드가없고 일반적인 코드 포인트 만 있으므로 그렇게 변환해야합니다. UTF-16의 진정한 장점은 UTF-8을 완전히 다시 쓰는 것보다 UCS-2 코드베이스를 업그레이드하는 것이 더 쉽다는 것입니다. 재미 있습니까?

1
물론, 기술적으로 UTF-16은 UCS-2의 상위 집합이 아니지만, U + D800에서 U + DFFF까지 언제 UTF-16 대리자를 제외한 다른 용도로 사용 되었습니까?
dan04

2
중요하지 않습니다. 바이트 스트림을 맹목적으로 통과하는 것 이외의 처리에는 대리 쌍을 디코딩해야하는데, UCS-2로 처리하는 경우 수행 할 수 없습니다.

6

UTF-16은 처리와 공간 사이 에서 가장 좋은 절충안 이므로 대부분의 주요 플랫폼 (Win32, Java, .NET)에서 문자열의 내부 표현에 사용합니다.


31
UTF-8은 더 작거나 크게 다르지 않기 때문에 -1입니다. 특정 아시아 스크립트의 경우 UTF-8은 글리프 당 3 바이트이지만 UTF-16은 2 개이지만 ASCII의 경우 UTF-8과 1 바이트 만 균형을 이룹니다 (제품 이름, 명령 등의 아시아 언어로도 표시됨). 소지품). 또한, 상기 언어들에서, 글리프는 라틴 문자보다 많은 정보를 전달하므로 더 많은 공간을 차지할 수있다.

32
나는 두 옵션의 최악의 측면을 결합하는 것이 좋은 타협이라고 부르지 않을 것입니다.

18
UTF-8보다 쉽지 않습니다. 길이도 가변적입니다.
luiscubal

36
UTF-16의 이점에 대한 토론을 남겨두고 인용 한 것은 UTF-16을 사용하는 Windows, Java 또는 .NET의 이유 가 아닙니다 . Windows와 Java는 유니 코드가 16 비트 인코딩이었던 시대로 거슬러 올라갑니다. 당시 UCS-2는 합리적인 선택이었습니다. 유니 코드가 21 비트 인코딩이되었을 때 UTF-16으로 마이그레이션하는 것이 기존 플랫폼의 최선의 선택이었습니다. 이는 취급 편의성 또는 공간 손상과 관련이 없습니다. 그것은 단지 유산의 문제입니다.
Joey

10
.NET은 여기서 Windows 레거시를 상속합니다.
Joey

6

UTF-16의 요점을 이해하지 못했습니다. 공간 효율적으로 표현하려면 UTF-8을 사용하십시오. 텍스트를 고정 길이로 처리하려면 UTF-32를 사용하십시오. 둘 다 원하지 않으면 UTF-16을 사용하십시오. 더 나쁜 것은 UTF-16의 모든 공통 (기본 다국어 평면) 문자가 단일 코드 포인트에 적합하기 때문에 UTF-16이 고정 길이라고 가정하는 버그는 미묘하고 찾기가 쉽지 않지만 UTF-8을 사용하면 국제화를 시도하자마자 코드가 빠르고 크게 실패합니다.


6

아직 댓글을 달 수 없기 때문에이 글에 대한 답변을 게시했습니다 utf8everywhere.org. 다른 스택 교환에 대한 평판이 충분하기 때문에 자동으로 주석 권한을 얻지 못하는 것은 부끄러운 일입니다.

이것은 의견에 대한 의견으로 사용됩니다. 예, UTF-16은 해로운 답변 으로 간주되어야합니다 .

약간의 수정 :

실수로 UTF-8 char*을 ANSI 문자열 버전의 Windows-API 함수 로 전달하지 못하게하려면 UNICODE, not을 정의해야합니다 _UNICODE. _UNICODE같은지도 기능 _tcslenwcslen,하지 MessageBoxMessageBoxW. 대신 UNICODE정의는 후자를 처리합니다. 증명을 위해 다음은 MS Visual Studio 2005의 WinUser.h헤더 에서 가져온 것입니다 .

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

최소한이 오류는에 수정되어야합니다 utf8everywhere.org.

제안:

어쩌면이 안내서에는 Wide- 문자열 버전의 데이터 구조를 명시 적으로 사용하는 예가 포함되어있어 놓치거나 잊어 버리기가 쉽지 않습니다. 와이드 스트링 버전의 함수를 사용하는 것 외에도 와이드 스트링 버전의 데이터 구조를 사용하면 실수로 그러한 함수의 ANSI 스트링 버전을 호출 할 가능성이 줄어 듭니다.

예제의 예 :

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
if (hSearch != INVALID_HANDLE_VALUE)
{
    FindClose(hSearch);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
}

합의 감사! 문서를 업데이트하겠습니다. 이 문서는 여전히 데이터베이스에 대한 추가 개발 및 정보 추가가 필요합니다. 우리는 표현의 공헌을 기쁘게 생각합니다.
Pavel Radzivilovsky

@PavelRadzivilovsky _UNICODE는 여전히 존재합니다 :(
cubuspl42

상기시켜 주셔서 감사합니다. cubus, Jelle SVN 사용자를 원하십니까?
Pavel Radzivilovsky

@Pavel 물론, 감사합니다!
Jelle Geerts

@JelleGeerts :이 지연에 대해 사과드립니다. 당신은 항상 우리의 이메일 (선언문에서 링크 됨) 또는 페이스 북으로 문의 할 수 있습니다. 우리는 쉽게 찾을 수 있습니다. 우리가 여기에서 가져온 문제를 해결했다고 생각하지만 (UTF-16 토론) 전체 UTF-8 토론은 여전히 ​​관련이 있습니다. 당신이 더 기여할 수 있다면 그 개인 채널을 통해 저희에게 연락 주시기 바랍니다.
ybungalobill 2016 년

5

누군가 UCS4와 UTF-32는 동일하다고 말했다. 아니,하지만 네가 무슨 뜻인지 알아 그러나 그중 하나는 다른 하나의 인코딩입니다. 나는 그들이 처음부터 엔디안을 지정한다고 생각했기 때문에 엔디안 전투도 여기서 일어나지 않을 것입니다. 그들이 오는 것을 보지 못했습니까? 누군가가 6 바이트의 원래 사양을 따르지 않는 한 UTF-8 이상은 모든 곳에서 동일합니다.

UTF-16을 사용하는 경우 멀티 바이트 문자 처리를 포함 해야 합니다. 2N을 바이트 배열로 인덱싱하여 N 번째 문자로 이동할 수 없습니다. 걸어가거나 문자 색인이 있어야합니다. 그렇지 않으면 당신은 버그를 작성했습니다.

C ++의 현재 초안 사양은 UTF-32 및 UTF-16이 리틀 엔디안, 빅 엔디안 및 지정되지 않은 변형을 가질 수 있다고 말합니다. 정말? 유니 코드가 모든 사람들이 처음부터 리틀 엔디안을해야한다고 명시했다면 모두 더 단순했을 것입니다. (빅 엔디안도 괜찮 았을 것입니다.) 대신, 어떤 사람들은 한 가지 방법으로, 다른 한 사람은 그것을 구현했지만, 우리는 아무것도 아닌 것에 대해 침묵에 갇혀 있습니다. 때로는 소프트웨어 엔지니어가 당혹 스럽기도합니다.


지정되지 않은 endianess는 첫 번째 문자로 BOM을 포함해야하며 문자열을 읽을 방법을 결정하는 데 사용됩니다. UCS-4와 UTF-32는 오늘날 동일합니다. 즉, 0과 0x10FFFF 사이의 숫자 UCS 값은 32 비트 정수로 저장됩니다.

5
@Tronic : 기술적으로 이것은 사실이 아닙니다. UCS-4는 32 비트 정수를 저장할 수 있지만 UTF-32는 0xFFFF, 0xFFFE 및 모든 대리자와 같이 상호 교환에 불법적 인 문자가 아닌 코드 포인트를 저장하지 못합니다. UTF는 내부 인코딩이 아닌 전송 인코딩입니다.
tchrist

다른 프로세서가 다른 바이트 순서를 계속 사용하는 한 엔디안 문제는 피할 수 없습니다. 그러나 UTF-16 파일 저장에 "바람직한"바이트 순서가 있으면 좋을 것입니다.
Qwertie

UTF-32는 코드 포인트의 고정 너비이지만 문자의 고정 너비는 아닙니다 . ( "combining characters"라는 말을 들었습니까?) 따라서 단순히 4N을 바이트 배열로 색인화 하여 N 번째 문자 로 이동할 수 없습니다 .
musiphil 2016 년

2

개발자가 충분히주의를 기울이면 해롭지 않다고 생각합니다.
그리고 그들이 잘 알고 있다면이 거래를 받아 들여야합니다.

일본의 소프트웨어 개발자로서 UCS-2가 충분히 크고 공간을 제한하면 로직을 단순화하고 런타임 메모리를 줄일 수 있으므로 UCS-2 제한에서 utf-16을 사용하면 충분합니다.

코드 포인트와 바이트가 비례한다고 가정하는 파일 시스템 또는 기타 응용 프로그램이 있으므로 원시 코드 포인트 번호가 고정 크기 저장소에 적합하도록 보장 할 수 있습니다.

UCS-2 를 파일 이름 스토리지 인코딩으로 지정하는 NTFS 및 VFAT 가 그 예입니다 .

이 예제가 UCS-4를 지원하기 위해 실제로 확장하려는 경우 어쨌든 모든 것에 utf-8 사용에 동의 할 수는 있지만 고정 길이는 다음과 같은 장점이 있습니다.

  1. 길이별로 크기를 보장 할 수 있습니다 (데이터 크기와 코드 포인트 길이는 비례합니다)
  2. 해시 조회에 인코딩 번호를 사용할 수 있습니다
  3. 비 압축 데이터의 크기는 합리적입니다 (utf-32 / UCS-4와 비교)

임베디드 / 임베디드 디바이스에서도 메모리 / 프로세싱 파워가 저렴할 경우, 캐시 누락이나 페이지 폴트 및 추가 메모리 사용으로 인해 디바이스 속도가 약간 느려질 수 있지만 가까운 시일 내에 발생하지는 않을 것입니다 ...


3
이 의견을 읽는 사람들에게는 UCS-2가 UTF-16과 같지 않다는 점에 주목할 가치가 있습니다. 이해하기 위해 차이점을 찾아보십시오.
mikebabcock 2014

1

"가장 인기있는 인코딩 중 하나 인 UTF-16이 유해한 것으로 간주되어야합니까?"

아마도 가능하지만 대안이 반드시 훨씬 더 나은 것으로 간주되어서는 안됩니다.

근본적인 문제는 글리프 (glyph), 문자, 코드 포인트 및 바이트 시퀀스에 대한 다양한 개념이 있다는 것입니다. 정규화 라이브러리를 사용하더라도 이들 각각의 매핑은 쉽지 않습니다. (예를 들어, 라틴어 기반 스크립트로 작성된 유럽 언어의 일부 문자는 단일 유니 코드 코드 포인트로 작성되지 않습니다. 이는 복잡성의 끝에서 더 간단합니다!) 이것이 의미하는 바는 모든 것을 정확하게 얻는 것이 매우 놀랍습니다. 어려운; 기괴한 버그가 예상됩니다. 여기에서 버그에 대해 신음하는 대신 관련 소프트웨어 관리자에게 알려주십시오 .

예를 들어 UTF-8과 달리 UTF-16이 유해한 것으로 간주 될 수있는 유일한 방법은 BMP 외부에서 코드 포인트를 인코딩하는 방법이 다릅니다 (대리인 한 쌍으로). 코드가 코드 포인트별로 액세스하거나 반복하려면 차이를 인식해야합니다. OTOH는 "문자"를 가정하는 기존 코드의 상당 부분이 항상 2 바이트 수량에 맞을 수 있다는 것을 의미합니다. 다시 말해, 적어도 제대로 처리되지 않은 캐릭터 를 보게 될 것입니다!

나는 당신의 질문을 머리에 돌리고 유니 코드의 모든 빌어 먹을 유해한 것으로 간주해야하며 모든 사람들은 (지난 20 년 동안) 내가 본 곳을 제외하고는 8 비트 인코딩을 사용해야한다고 말합니다. 다양한 ISO 8859 인코딩과 Cyrillic 및 EBCDIC 제품군에 사용 된 전체 세트를 혼동 할 수 있습니다. 다른 나라의 오해들 사이에서 그렇게 타협하지 않은 경우에만.


우리의 운을 알면 몇 년 안에 UTF-16의 공간이 부족해질 것입니다. Meh.
Donal Fellows

3
근본적인 문제는 텍스트가 기만적으로 어렵다는 것입니다. 그 정보를 디지털 방식으로 표현하는 방법은 복잡 할 수 없습니다. 디지털 머신이 인간의 문화적 구성과 교차 할 때마다 복잡성이 폭발 할 때마다 날짜가 어려워지고, 달력이 어려우며, 시간이 어려우며, 개인 이름이 어려우며, 우편 주소가 어려워지는 것과 같은 이유입니다. 인생의 사실입니다. 인간은 디지털 로직에서 기능하지 않습니다.
아리스토텔레스 Pagaltzis 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.