1. 개요
문자열 데이터를 처리할 때, 인코딩 방식에 따라 문자의 바이트 구조가 달라진다. 특히, ASCII 문자는 단일 바이트로 표현되지만, UTF-8, ANSI, EUC-KR, CP949와 같은 인코딩에서는 비ASCII 문자가 여러 바이트로 표현될 수 있다.
이 글에서는 각 인코딩 방식의 바이트 구조와 특징을 비교하고, 이를 C 코드로 처리하는 방법을 소개한다. 특히 한글과 같은 다중 바이트 문자를 정확히 판별하고 처리하기 위한 실용적인 접근법을 제시한다.
2. 인코딩별 문자 구조와 판별법
2.1. ASCII
- 범위
- 0x00 ~ 0x7F (0 ~ 127)
- 특징
- 모든 문자가 1바이트로 표현된다.
- 판별법
- 바이트 값이 0x00 ~ 0x7F에 해당하면 ASCII 문자이다.
2.2. UTF-8
UTF-8은 가변 길이의 문자 인코딩 방식으로, 문자에 따라 1~4바이트를 사용한다. 첫 번째 바이트는 문자 길이를 결정하며, 이어지는 바이트들은 특정 비트 패턴을 따른다.
2.2.1. 첫 번째 바이트의 규칙
첫 번째 바이트 | 바이트 수 | 코드포인트 범위 | 설명 |
0xxxxxxx | 1 | U+0000 ~ U+007F | ASCII 문자 |
110xxxxx | 2 | U+0080 ~ U+07FF | 2바이트 문자 |
1110xxxx | 3 | U+0800 ~ U+FFFF | 3바이트 문자 |
11110xxx | 4 | U+10000 ~ U+10FFFF | 4바이트 문자 |
2.2.2. 바이트 패턴
- 1바이트 (ASCII): 0xxxxxxx
- 예: 'A' (U+0041) → 0x41
- 2바이트: 110xxxxx 10xxxxxx
- 예: 'Ç' (U+00C7) → 0xC3 0x87
- 3바이트: 1110xxxx 10xxxxxx 10xxxxxx
- 예: '한' (U+D55C) → 0xED 0x95 0x9C
- 4바이트: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- 예: '😊' (U+1F60A) → 0xF0 0x9F 0x98 0x8A
2.2.3. UTF-8의 제한 사항
- 최소 바이트 수 사용
- 가능한 최소 바이트로만 표현해야 한다.
- Surrogate 영역 금지
- U+D800 ~ U+DFFF는 UTF-8에서 사용할 수 없다.
2.3. ANSI와 CP949
ANSI는 특정 지역(로컬) 환경의 문자 세트를 표현하기 위한 인코딩이며, 한국어 환경에서는 CP949를 의미한다.
2.3.1. ANSI의 바이트 구조
- 1바이트 문자: 0x00 ~ 0x7F
- ASCII와 동일하다.
- 2바이트 문자:
- 첫 번째 바이트 (Lead Byte): 0x81 ~ 0xFE
- 두 번째 바이트 (Trail Byte): 0x41 ~ 0xFE
2.3.2. CP949의 특징
- KS X 1001(구 KS C 5601) 기반의 한국어 완성형 문자를 지원한다.
- 한글 11,172자를 포함한 확장 문자를 지원한다.
- EUC-KR을 기반으로 더 많은 문자를 표현한다.
2.4. EUC-KR
EUC-KR은 한국어 완성형 문자를 지원하기 위해 설계된 고정 길이 2바이트 문자셋이다.
2.4.1. 바이트 구조
- 1바이트 문자: 0x00 ~ 0x7F (ASCII와 동일).
- 2바이트 문자:
- 첫 번째 바이트: 0xA1 ~ 0xFE
- 두 번째 바이트: 0xA1 ~ 0xFE
2.4.2. EUC-KR과 CP949 비교
구분 | EUC-KR | CP949 |
1바이트 문자 | ASCII (0x00 ~ 0x7F) | ASCII (0x00 ~ 0x7F) |
2바이트 문자 | Lead: 0xA10xFE, Trail: 0xA10xFE | Lead: 0x810xFE, Trail: 0x410xFE |
지원 문자 수 | 한글 2,350자 | 한글 11,172자 |
3. 다양한 인코딩 처리 방법
다음은 C 코드로 ASCII, UTF-8, ANSI(CP949), EUC-KR 문자를 판별하고 처리하는 예제이다.
#include <stdio.h>
typedef struct CharCounter {
unsigned int asciiCount; // ASCII 문자 개수
unsigned int cp949TwoByteCount; // CP949 2바이트 문자 개수
unsigned int utf8ThreeByteCount; // UTF-8 3바이트 문자 개수
unsigned int utf8FourByteCount; // UTF-8 4바이트 문자 개수
} CharCounter;
void AnalyzeCharEncoding(CharCounter *counter, unsigned char currentByte) {
static unsigned char currentState = 0; // 현재 상태 (0: 기본, 1: CP949 첫 바이트, 2: UTF-8 처리 중)
static unsigned int utf8BytesRemaining = 0; // UTF-8 남은 바이트 수
static unsigned char firstByte = 0; // CP949 첫 바이트 저장
if (currentState == 1) { // CP949 두 번째 바이트 확인
if (currentByte >= 0x41 && currentByte <= 0xFE) { // CP949 두 번째 바이트 조건
counter->cp949TwoByteCount++;
}
currentState = 0; // 상태 초기화
} else if (utf8BytesRemaining > 0) { // UTF-8 처리 중
if ((currentByte & 0xC0) == 0x80) { // UTF-8 연속 바이트 확인
utf8BytesRemaining--;
if (utf8BytesRemaining == 0) { // UTF-8 문자 완성
counter->utf8ThreeByteCount++;
currentState = 0; // 상태 초기화
}
} else {
// UTF-8 형식이 아니면 CP949 두 번째 바이트로 판단
if (currentByte >= 0x41 && currentByte <= 0xFE) {
counter->cp949TwoByteCount++;
}
currentState = 0; // 상태 초기화
}
} else if ((currentByte & 0xF0) == 0xE0) { // UTF-8 3바이트 문자 시작
utf8BytesRemaining = 2; // 남은 바이트 수 설정
currentState = 2; // UTF-8 상태로 설정
} else if ((currentByte >= 0x81 && currentByte <= 0xFE)) { // CP949 첫 바이트
currentState = 1; // CP949 상태 설정
firstByte = currentByte; // 첫 바이트 저장
} else if (currentByte <= 0x7F) { // ASCII 문자
counter->asciiCount++;
} else {
// 알 수 없는 문자 → 상태 초기화
currentState = 0;
}
}
int main() {
CharCounter counter = {0};
unsigned char testInput[] = {0x41, 0xE0, 0x41, 0xE0, 0x80, 0x80, 0xB0, 0xA1, 0x43, 0};
int index = 0;
while (testInput[index]) {
AnalyzeCharEncoding(&counter, testInput[index]);
index++;
}
printf("ASCII 문자 개수: %d\n", counter.asciiCount);
printf("CP949 2바이트 문자 개수: %d\n", counter.cp949TwoByteCount);
printf("UTF-8 3바이트 문자 개수: %d\n", counter.utf8ThreeByteCount);
printf("UTF-8 4바이트 문자 개수: %d\n", counter.utf8FourByteCount);
return 0;
}
4. 결론
문자열 데이터를 처리할 때, 각 인코딩의 특징과 바이트 구조를 이해하는 것이 중요하다.
- ASCII: 단일 바이트 문자.
- UTF-8: 가변 길이 인코딩으로 유니코드와 확장 문자를 지원한다.
- ANSI/CP949: 지역별 문자 지원. 한국어 환경에서는 CP949로 사용한다.
- EUC-KR: 고정 길이 2바이트 문자셋으로, CP949에 비해 한계가 있다.
각 인코딩의 규칙을 정확히 이해하고, 적절한 처리를 통해 다양한 문자셋을 지원하는 안정적인 프로그램을 개발할 수 있다.
728x90
'기술 노트' 카테고리의 다른 글
UTF-16 인코딩 방식의 이해와 실무 적용 팁 (0) | 2025.01.09 |
---|---|
메모리 할당 전략 비교: 1MB * 100 vs 100MB * 1 (0) | 2025.01.07 |
Windows 고성능 타이머 사용법: QueryPerformanceFrequency와 QueryPerformanceCounter (0) | 2025.01.06 |
이진탐색(Binary Search) 완벽 가이드 (1) | 2025.01.05 |
Shunting Yard 알고리즘: 중위 표기법에서 후위 표기법으로 (1) | 2025.01.04 |