문자열 처리 (인코딩)

문자열 방식

SBCS(Single Byte Character Set)

  1. SBCS(Single Byte Character Set)는 1바이트로 문자를 표현하는 문자 집합이다. ASCII 문자 집합을 기반으로 만들어졌다. SBCS는 주로 컴퓨터 시스템의 호환성 유지를 위해 사용된다.
  2. ASCII
    7bit로 영문자, 숫자, 특수문자, 기호 등 128개 문자를 표현할 수 있다. 1bit는 Parity Bit로 통신 에러 검출을 위해 사용된다.
  3. ANSI
    8bit로 구성되어 있으며 256개의 문자를 표현할 수 있다. (ASCII의 확장판) ANSI의 앞 7bit는 ASCII와 동일하고, 뒤에 1bit를 이용하여 다른 언어의 문자를 표현한다.
    새로 추가된 128개 문자(뒤에 1bit)로는 모든 언어의 문자를 표현할 수 없다. 그래서 생긴 개념이 CodePage이다.

MBCS(Multi Byte Character Set)

  1. MBCS(Multi Byte Character Set)는 한 문자를 표현하는 데 1바이트 이상을 사용한다. 문자당 여러 개의 바이트를 사용하기 때문에 다국어 문자 집합을 지원할 수 있다.
  2. 대부분 2바이트를 사용하기 때문에 DBCS(Double Byte Character Set)라고도 부른다. 이론상으로 MBCS는 3바이트 이상의 문자도 포함할 수 있다.
  3. MBCS는 SBCS보다 복잡하고 느리지만, 다국어를 처리할 수 있기 때문에 한국어(EUC-KR), 일본어(Shift-JIS), 중국어(GB2312)를 표현하기 위해 많이 사용된다.
  4. MBCS는 다양한 언어를 지원할 수 있지만, 문자열 처리에서 오류가 발생할 수 있다.
    1. 국가간의 호환이 되지 않는 방식이기에 다른 시스템으로 보내면 글자가 깨진다.
    2. 문자열의 길이를 계산할 때 한 문자가 1바이트 이상일 수 있기 때문에 문자열의 길이를 정확히 계산하기 어렵다.
    3. MBCS를 사용하는 경우 문자열 처리에 주의할 사항이 많기 때문에 프로그래밍 복잡성이 증가한다.
  5. 호환성 문제
    1. Microsoft Windows의 경우 유니코드를 지원하지 않았던 Windows 9x와의 호환성을 위해 여전히 MBCS를 기본 인코딩으로 사용한다.
    2. UTF-8이나 UTF-16에 BOM(바이트 순서 표식) 문자가 없으면 무조건 MBCS로 읽어들이는 프로그램들이 존재하기 때문에 Windows용 프로그램들은 UTF-8로 저장 시 BOM을 붙이는 경우가 많은데, 이는 BOM이 없는 UTF-8을 사용하는 타 운영체제에서 인코딩 오류를 일으키게 된다.
    3. UTF-8을 기본 인코딩으로 도입한 macOS나 2000년대 이후의 리눅스 등은 기본적으로 텍스트 파일을 단일 인코딩으로 읽어들이기 때문에 MBCS 형태로 작성된 텍스트 파일은 별도의 처리를 하지 않는 한 전부 ?로 보인다.

DBCS(Double Byte Character Set)

  1. DBCS(Double Byte Character Set)는 2바이트 이상의 다중 바이트 문자를 사용하는 문자 집합이다. SBCS와 MBCS의 한계를 극복하기 위해 나온 방식으로, 한글, 중국어, 일본어와 같은 문자열 처리에 사용된다.
  2. DBCS는 MBCS와 유사하지만, 한 문자를 표현하기 위해 2바이트 이상을 사용하며, 모든 문자가 같은 길이의 바이트를 사용하지 않는다. 문자당 사용하는 바이트 수가 고정되어 있지 않아 SBCS나 MBCS보다 복잡하고 느릴 수 있다.
  3. 이러한 문제점으로 인해 유니코드를 사용하는 것이 일반적이다.

WBCS(Wide Byte Character Set)

  1. WBCS(Wide Byte Character Set)는 한 문자를 표현하기 위해 2바이트를 사용하는 문자 집합이다. MBCS와 달리, 모든 문자가 같은 길이의 바이트를 사용하기 때문에 문자열 처리에서 발생할 수 있는 문제점을 해결할 수 있다.
  2. WBCS는 주로 유니코드(Unicode)를 기반으로 하며, 다양한 언어와 문자를 지원할 수 있다. 유니코드는 전 세계의 모든 문자를 표현하기 위한 국제 표준이며, WBCS는 유니코드를 사용하여 다국어 문자열을 처리하기 위한 방법 중 하나이다.
  3. WBCS는 여러 개의 바이트를 사용하기 때문에, SBCS보다는 더 복잡하고 느리지만, 다양한 언어와 문자를 지원할 수 있어 현대의 다국어 시스템에서 많이 사용된다. WBCS를 사용하면 한 문자당 사용하는 바이트 수가 고정되어 있기 때문에 문자열 처리가 더 간단해집니다.
  4. WBCS는 다국어를 처리하는 데에는 적합하지만, 바이트 수가 크기 때문에 메모리와 디스크 공간을 많이 사용한다. 다국어를 처리하지 않는 시스템에서는 SBCS나 MBCS를 사용하는 것이 더 효율적일 수 있다.
  5. 대표적인 WBCS로는 UTF-8, UTF-16 등이 있다. UTF-8은 8비트로 문자를 표현하고, UTF-16은 16비트로 문자를 표현한다. 또한 바이트 순서를 지정하는 방법에 따라서 Big-Endian과 Little-Endian으로 나뉜다.

유니코드 (Unicode)

  1. 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰수 있도록 설계된 표준이다.
  2. 숫자와 글자, 키와 값이 1:1로 매핑된 형태의 코드로 전 세계의 모든 문자를 특정 숫자(키)와 1:1로 매핑한 것이다.
  3. UTF-8, UTF-16은 유니코드를 사용하는 인코딩 방식이다. 인코딩 방식은 유니코드표의 숫자(키)를 어떻게 표현하느냐에 따른 방식이다.
    1. UTF-8은 'A'를 0x41로 표현한다.
    2. UTF-16은 'A'를 0x0041로 표현한다.
  4. 'U+' 접두어가 붙어 있으면 유니코드 라는 의미이다.

 

윈도우에서의 문자열

CP949 / EUC-KR / UTF-8 이 혼합되어 사용됨.

C++로 컴파일을 하면 유니코드를 쓸지 멀티바이트를 쓸지 옵션으로 선택할 수 있음.

  1. 코드를 짤때 이 문자열 "" 방식이 중요함
    1. "" 멀티바이트, char
    2. L"" 유니코드, wchar
    3. _T("") 매크로, 옵션에 따라 멀티바이트/유니코드를 선택적으
  2. 파일 저장시 파일을 UTF-8 형식으로 저장할지 EUC-KR 형태로 저장할지 중요함.

2번 설정과 시스템에 언어에 따라 애플리케이션의 한글이 깨져보이는 현상이 있음.

 

웹페이지에서의 문자열

기본 타입 EUC-KR / UTF-8 (국내 웹페이지), header 에 meta 태그로 아래와 같이 정의

  1. <meta charset="euc-kr" />
  2. <meta charset="utf-8" />
  3. <meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

최근에는 UTF-8 로 통일되는 형태, 웹페이지와 통신하는 서버도 UTF8 형식으로 바꿈

 

MySql / MariaDB 에서의 문자열

위 이슈와 맞출려 서버 DB에 문자열 셋 영향이 있음

  1. mysql 기본 문자열은 latin1_swedish_ci = latin1 (cp1252 West European)
  2. 2000년대 초는 euckr_korean_ci = euckr (EUC-KR Korean): 2 바이트 고정
  3. 200년대 후반 utf8_general_ci = utf8 (UTF-8 Unicode): 3 바이트 가변
  4. 2010년 이후 utf8mb4_unicode_ci = utf8mb4 (UTF-8 Unicode): 4 바이트 고정
참고, 이모지 코드는 온전한 4바이트가 필요하기 때문에 utf8mb4 로 바꾸어야 저장된다.

여전히 기본 문자열은 latin1 으로 세팅되기 때문에 DB를 생성하던지 테이블을 생성할때 utf8mb4 지정이 필요하다.

 

일렉트론(electron) 에서의 문자열

기본 타입 UTF-8

  1. 웹페이지가 대부분 utf-8 로 만들어지면서 문자열을 다른 문자열로 변환해야하는 이슈가 없어짐.

 

러스트(Rust) 에서의 문자열

기본 타입 UTF-8, 기본 문자열 타입

  1. String: 할당이 필요한 가변형으로 Vec<char> 구조체
    1. 할당해서 쓰므로 힙 영역에 할당되고 Vec 형태이므로 가변 형태로 상용 가능
    2. Vec 이므로 C++ 처럼 null 로 끝나지 않음.
  2. &Str: 고정문자 ("") 스텍영역에 저장

2번에 String 이 Vec 기반에 가변문자열이기 때문에 "" 문자를 넣기 위해서는 메모리 할당 혹은 문자열 변경이 필요하다.

  1. 기본 문자열은 UTF-8 3바이트(한글) 문자이기 때문에
    1. 다음과 같은 문자열은 메모리 상에 b 처럼 저장된다.
      1. 예) "c:\\users\\한글\\경로포함" 
    2. "c:\\users\\\xed\x95\x9c\xea\xb8\x80\\\xea\xb2\xbd\xeb\xa1\x9c\xed\x8f\xac\xed\x95\xa8"
    3. 이 문자열을 10진수로 확인해보면 아래와 같다.
      1. 99 58 92 117 115 101 114 115 92 -19 -107 -100 -22 -72 -128 92 -22 -78 -67 -21 -95 -100 -19 -113 -84 -19 -107 -88
  1. 네이티브 플랫폼에서 사용되는 문자열 타입
    1. OsString / &OsStr
  2. 이 문자열을 4번과 같이 출력해 보면
    1. 다음과 같은 문자열은 메모리 상에 b 처럼 저장된다.
      1. 예) "c:\\users\\한글\\경로포함" 
    2. "c:\\users\\한글\\경로포함"

일렉트론 / 러스트 와 C++ 코드간에 문자열 연동

  1. 일렉트론과 러스트는 기본적으로 UTF-8 문자열을 사용하기 때문에 특별한 이슈가 없다.
  2. 러스트와 C++ 코드간에 영문을 전달할때 특별한 이슈가 없다.
  3. C++ 코드에서 wchar (2바이트) 가 필요한 경우 utf-8 (3바이트) 문자열을 넘기면 인식할 수 없기에 변환이 필요하다.
  4. 위 러스트 문자열 중 OsString 가 2바이트 형태로 바뀌주나 이걸 wchar 형태로 내보낼 맴버를 찾지 못했다.
    1. 가이드 문서에는 아래와 같은 함수가 있다고 나오나 실제 빌드를 하면 없다고 나음
      1. fn into_os_str_bytes(self) -> Vec<u8> 
      2. fn as_os_str_ptr(self) -> Vec<u8> 
  5. 그래서 찾은 방법이 두 자지 모듈 인데
    1. encoding_rs 에 EUC_KR::encode 이용하여 2바이트 Vec 로 바꾼뒤 null 문자를 포함시키고 C++코드에서 wchar 로 바꾸
      1. 코드는 정상동작하나 C++코드에서 wchar 로 변경한 경우 C++코드에서 메모리 할당 및 해제가 필요해 번거러움
    2. widestring 에  U16CString 를 이용하여 변환 ptr (wchar) 바꾸기
      1. 테스트 결과 U16CString 에서 변환하면서 메모리를 할당하고 해제하기 때문에 사용하기 편함.

 

맥 OS 에서의 문자열

UTF8 은 조금 더 세부적으로 아래와 같이 표현된다. [출처]

제목묘사
정규화 방식 D (NFD) 정준 분해
정규화 방식 C (NFC) 정준 분해한 뒤에 다시 정준 결합
정규화 방식 KD (NFKD) 호환 분해
정규화 방식 KC (NFKC) 호환 분해한 뒤에 다시 정준 결합

NFD (Normalize Form D)

NFD는 모든 음절을 Canonical Decomposition(정준 분해)하여 한글 자모 코드를 이용하여 저장하는 방식이다. 즉, 각을  +  +  로 저장하는 방식이다. 이 방식은 현대 한글과 옛 한글을 동일한 방식으로 저장한다는 장점이 있지만 NFC 방식과 비교하여 텍스트의 크기가 커진다는 문제가 있다.

NFD는 macOS 시스템에서 주로 사용한다.

NFC (Normalize Form C)

NFC는 모든 음절을 Canonical Decomposition(정준 분해) 후 Canonical Composition(정준 결합) 하는 방식이다. 즉, 각을 각이라는 하나의 문자로 저장하는 방식이다. 이 방식을 사용하면 NFD 방식보다 텍스트의 사이즈는 작아지게 된다. 하지만, 옛 한글 자모의 결합으로 이루어진 한글 음절 코드가 없으므로 이 음절은 Canonical Composition 하지 못하므로 자소가 분리된 체로 저장하게 된다. 이로 인해, 현대 한글과 옛 한글이 다른 방식으로 저장되므로 텍스트를 처리할 때 유의해야 한다.

NFC는 많은 GNU/Linux 시스템, Windows에서 주로 사용한다.

NFKC, NFKD

NFKC와 NFKD는 또 다른 NFC, NFD 정규화 방식이다. 많은 사람들이 NFC와 NFD만 한글 유니코드를 처리하는데 쓰이고 NFKD/NFD, NFKC/NFC의 차이가 없다고 생각한다. 이는 한글 음절/자모 유니코드에서 호환분해 과정과 정준분해 과정이 동일하기 때문에 생기는 인식이다.

NFKC와 NFKD는 한글자모/한글음절 영역 이외의 한글 유니코드 영역을 처리할 때 유용하게 사용할 수 있다. 다음 표를 참고하면 각 유니코드 클자가 정규화 방식에 따라 어떻게 변하는 가를 확인할 수 있다.

'개발 > 기타' 카테고리의 다른 글

[macOS] 인텔 맥북 터보 부스터 끄기  (0) 2024.10.15
[공통] 폰트  (0) 2024.10.10
Chromium Codec, Containers and File Extensions Support  (0) 2023.10.27
BananaPI  (0) 2023.10.27
CEF (Chromium Embedded Framework)  (0) 2023.10.27