[2026] 문자 인코딩 완벽 가이드 | ASCII·UTF-8·UTF-16·EUC-KR 총정리
이 글의 핵심
ASCII, ANSI, Unicode, UTF-8, UTF-16, UTF-32, EUC-KR, CP949 등 모든 문자 인코딩 방식의 원리와 차이점. 한글 깨짐 문제 해결부터 BOM, Endian까지 실전 예제로 완벽 이해.
들어가며: 왜 문자 인코딩을 알아야 하나?
개발하다 보면 한글이 깨지거나, 파일을 읽을 수 없거나, API 응답이 이상하게 나오는 경험을 합니다. 이 모든 문제의 근본 원인은 문자 인코딩입니다. 이 글에서 다룰 내용:
- ASCII, ANSI, Unicode의 역사
- UTF-8, UTF-16, UTF-32 인코딩 방식
- 한글 인코딩 (EUC-KR, CP949)
- BOM, Endian, 인코딩 감지
- 실전 문제 해결
실무에서 마주한 현실
개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.
목차
- 문자 인코딩의 역사
- ASCII: 7비트 문자 집합
- ANSI와 코드 페이지
- Unicode: 전 세계 문자 통합
- UTF-8: 가변 길이 인코딩
- UTF-16과 UTF-32
- 한글 인코딩 (EUC-KR, CP949)
- BOM과 Endian
- 실전 문제 해결
- 프로그래밍 언어별 처리
1. 문자 인코딩의 역사
타임라인
아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
timeline
title 문자 인코딩 발전사
1963 : ASCII 제정\n7비트, 128자
1987 : ISO-8859-1 (Latin-1)\n8비트, 256자
1991 : Unicode 1.0\n16비트 통합 문자셋
1992 : UTF-8 발명\n가변 길이 인코딩
1996 : UTF-16\n서로게이트 페어
2003 : UTF-8 웹 표준화
2008 : UTF-8이 웹에서\n가장 많이 사용
2026 : UTF-8 점유율 98%
왜 여러 인코딩이 존재하나?
아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
flowchart TB
Problem["문제: 컴퓨터는\n숫자만 이해"]
ASCII["ASCII\n영문 128자"]
Extended["확장 ASCII\n각국 언어 256자"]
Unicode["Unicode\n전 세계 문자 통합"]
Problem --> ASCII
ASCII --> Extended
Extended --> Unicode
ASCII --> Issue1["문제: 한글, 한자\n표현 불가"]
Extended --> Issue2["문제: 각국마다\n다른 코드 페이지"]
Unicode --> Solution["해결: 모든 문자에\n고유 번호 부여"]
2. ASCII: 7비트 문자 집합
ASCII란?
ASCII(American Standard Code for Information Interchange)는 7비트(0-127)로 영문 알파벳, 숫자, 특수문자를 표현합니다.
ASCII 테이블
아래 코드는 code를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
Dec Hex Char | Dec Hex Char | Dec Hex Char
-------------------------------------------------
32 20 Space | 64 40 @ | 96 60 `
33 21 ! | 65 41 A | 97 61 a
34 22 " | 66 42 B | 98 62 b
35 23 # | 67 43 C | 99 63 c
...
48 30 0 | 80 50 P | 112 70 p
49 31 1 | 81 51 Q | 113 71 q
...
57 39 9 | 90 5A Z | 122 7A z
ASCII 제어 문자
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 주요 제어 문자
NUL = 0x00 # Null
LF = 0x0A # Line Feed (\n)
CR = 0x0D # Carriage Return (\r)
ESC = 0x1B # Escape
DEL = 0x7F # Delete
# 줄바꿈 방식
# Unix/Linux: LF (\n)
# Windows: CR+LF (\r\n)
# Mac (Classic): CR (\r)
ASCII 예제
다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 문자 → 코드
ord('A') # 65
ord('a') # 97
ord('0') # 48
# 코드 → 문자
chr(65) # 'A'
chr(97) # 'a'
# ASCII 범위 확인
def is_ascii(text):
return all(ord(c) < 128 for c in text)
is_ascii("Hello") # True
is_ascii("안녕") # False
3. ANSI와 코드 페이지
ANSI란?
ANSI는 8비트(0-255)로 확장하여 각국 언어를 지원합니다. 하지만 코드 페이지(Code Page)마다 128-255 범위의 의미가 다릅니다.
주요 코드 페이지
| 코드 페이지 | 이름 | 지역 | 특징 |
|---|---|---|---|
| CP437 | OEM-US | 미국 | DOS 기본 |
| CP850 | Latin-1 | 서유럽 | DOS 다국어 |
| CP949 | 확장 완성형 | 한국 | Windows 한글 |
| CP932 | Shift-JIS | 일본 | Windows 일본어 |
| CP936 | GBK | 중국 | Windows 중국어 |
| ISO-8859-1 | Latin-1 | 서유럽 | Unix/Web |
| ISO-8859-15 | Latin-9 | 서유럽 | 유로(€) 추가 |
코드 페이지 문제
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 같은 바이트 값이 다른 의미
byte_value = 0xC7
# CP949 (한글): '한'
text_korean = byte_value.to_bytes(1, 'big').decode('cp949') # 에러 (2바이트 필요)
# ISO-8859-1 (Latin-1): 'Ç'
text_latin = byte_value.to_bytes(1, 'big').decode('latin-1') # 'Ç'
# 같은 파일을 다른 인코딩으로 읽으면 깨짐!
4. Unicode: 전 세계 문자 통합
Unicode란?
Unicode는 전 세계 모든 문자에 고유한 코드 포인트(Code Point)를 부여한 문자 집합입니다.
Unicode 구조
아래 코드는 code를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
U+0000 ~ U+10FFFF (1,114,112개 코드 포인트)
U+0000 ~ U+007F : ASCII (128자)
U+0080 ~ U+00FF : Latin-1 Supplement
U+0100 ~ U+017F : Latin Extended-A
U+0370 ~ U+03FF : Greek
U+0400 ~ U+04FF : Cyrillic
U+0600 ~ U+06FF : Arabic
U+0E00 ~ U+0E7F : Thai
U+3040 ~ U+309F : Hiragana (일본어)
U+30A0 ~ U+30FF : Katakana (일본어)
U+4E00 ~ U+9FFF : CJK Unified Ideographs (한중일 한자)
U+AC00 ~ U+D7AF : Hangul Syllables (한글 11,172자)
U+1F600 ~ U+1F64F : Emoticons (이모지)
한글 Unicode 범위
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 한글 음절 (가-힣)
print(f"가: U+{ord('가'):04X}") # U+AC00
print(f"힣: U+{ord('힣'):04X}") # U+D7A3
# 한글 자모 (ㄱ-ㅎ, ㅏ-ㅣ)
print(f"ㄱ: U+{ord('ㄱ'):04X}") # U+3131
print(f"ㅎ: U+{ord('ㅎ'):04X}") # U+314E
print(f"ㅏ: U+{ord('ㅏ'):04X}") # U+314F
print(f"ㅣ: U+{ord('ㅣ'):04X}") # U+3163
# 이모지
print(f"😀: U+{ord('😀'):04X}") # U+1F600
Unicode vs 인코딩
아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
Unicode: 문자 집합 (Character Set)
각 문자에 번호(코드 포인트) 부여
예: '한' = U+D55C
UTF-8/UTF-16/UTF-32: 인코딩 방식 (Encoding)
코드 포인트를 바이트로 변환하는 방법
예: U+D55C → UTF-8: ED 95 9C (3바이트)
→ UTF-16: D5 5C (2바이트)
5. UTF-8: 가변 길이 인코딩
UTF-8이란?
UTF-8은 1-4바이트 가변 길이로 Unicode를 인코딩합니다. 웹 표준이며, ASCII와 완벽히 호환됩니다.
UTF-8 인코딩 규칙
아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
코드 포인트 범위 | 바이트 수 | 인코딩 패턴
U+0000 ~ U+007F | 1바이트 | 0xxxxxxx
U+0080 ~ U+07FF | 2바이트 | 110xxxxx 10xxxxxx
U+0800 ~ U+FFFF | 3바이트 | 1110xxxx 10xxxxxx 10xxxxxx
U+10000 ~ U+10FFFF | 4바이트 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8 인코딩 예시
영문 ‘A’ (U+0041)
아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
코드 포인트: U+0041 (65)
이진수: 0100 0001
UTF-8 인코딩:
0100 0001 = 0x41 (1바이트)
메모리: 41
한글 ‘한’ (U+D55C)
아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
코드 포인트: U+D55C (54,620)
이진수: 1101 0101 0101 1100
UTF-8 인코딩 (3바이트):
1110xxxx 10xxxxxx 10xxxxxx
1110 1101 10 010101 10 011100
E D 9 5 9 C
메모리: ED 95 9C
이모지 ’😀’ (U+1F600)
아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
코드 포인트: U+1F600 (128,512)
이진수: 0001 1111 0110 0000 0000
UTF-8 인코딩 (4바이트):
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
11110 000 10 011111 10 011000 10 000000
F 0 9 F 9 8 8 0
메모리: F0 9F 98 80
UTF-8 장점
아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
flowchart TB
UTF8[UTF-8]
Adv1["✅ ASCII 호환\n영문은 1바이트"]
Adv2["✅ 자기 동기화\n중간부터 읽기 가능"]
Adv3["✅ 바이트 순서 무관\nEndian 문제 없음"]
Adv4["✅ 웹 표준\n98% 점유율"]
UTF8 --> Adv1
UTF8 --> Adv2
UTF8 --> Adv3
UTF8 --> Adv4
Python으로 UTF-8 인코딩
# 문자열 → 바이트
text = "Hello 한글 😀"
# UTF-8 인코딩
utf8_bytes = text.encode('utf-8')
print(utf8_bytes)
# b'Hello \xed\x95\x9c\xea\xb8\x80 \xf0\x9f\x98\x80'
# 바이트 분석
for i, byte in enumerate(utf8_bytes):
print(f"{i:2d}: 0x{byte:02X} ({byte:3d}) {chr(byte) if byte < 128 else '?'}")
# 출력:
# 0: 0x48 ( 72) H
# 1: 0x65 (101) e
# 2: 0x6C (108) l
# 3: 0x6C (108) l
# 4: 0x6F (111) o
# 5: 0x20 ( 32)
# 6: 0xED (237) ? ← '한' 시작
# 7: 0x95 (149) ?
# 8: 0x9C (156) ?
# 9: 0xEA (234) ? ← '글' 시작
# 10: 0xB8 (184) ?
# 11: 0x80 (128) ?
# 12: 0x20 ( 32)
# 13: 0xF0 (240) ? ← '😀' 시작
# 14: 0x9F (159) ?
# 15: 0x98 (152) ?
# 16: 0x80 (128) ?
# 바이트 → 문자열
decoded = utf8_bytes.decode('utf-8')
print(decoded) # "Hello 한글 😀"
6. UTF-16과 UTF-32
UTF-16
UTF-16은 2바이트 또는 4바이트로 인코딩합니다. Windows, Java, JavaScript 내부에서 사용됩니다.
UTF-16 인코딩 규칙
코드 포인트 범위 | 바이트 수 | 방식
U+0000 ~ U+FFFF | 2바이트 | 그대로 인코딩
U+10000 ~ U+10FFFF | 4바이트 | 서로게이트 페어
서로게이트 페어 (Surrogate Pair)
다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 이모지 '😀' (U+1F600)를 UTF-16으로 인코딩
# 1. U+1F600 - 0x10000 = 0xF600
# 2. 상위 10비트: 0x3D (61)
# 3. 하위 10비트: 0x200 (512)
# 4. High Surrogate: 0xD800 + 0x3D = 0xD83D
# 5. Low Surrogate: 0xDC00 + 0x200 = 0xDE00
text = "😀"
utf16_bytes = text.encode('utf-16-le')
print(utf16_bytes.hex()) # '3dd8 00de' (Little-Endian)
# UTF-16 BE (Big-Endian)
utf16_be = text.encode('utf-16-be')
print(utf16_be.hex()) # 'd83d de00'
UTF-16 예시
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
text = "Hello 한글"
# UTF-16 LE (Little-Endian)
utf16_le = text.encode('utf-16-le')
print(utf16_le.hex())
# 48 00 65 00 6c 00 6c 00 6f 00 20 00 5c d5 00 ae 00 b8
# UTF-16 BE (Big-Endian)
utf16_be = text.encode('utf-16-be')
print(utf16_be.hex())
# 00 48 00 65 00 6c 00 6c 00 6f 00 20 d5 5c ae 00 b8 00
UTF-32
UTF-32는 모든 문자를 4바이트 고정 길이로 인코딩합니다. 아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
text = "A한😀"
# UTF-32 LE
utf32 = text.encode('utf-32-le')
print(utf32.hex())
# 41 00 00 00 5c d5 00 00 00 f6 01 00
# 각 문자가 정확히 4바이트
# 'A': 0x00000041
# '한': 0x0000D55C
# '😀': 0x0001F600
인코딩 비교
text = "Hello 한글 😀"
encodings = ['utf-8', 'utf-16-le', 'utf-16-be', 'utf-32-le']
for enc in encodings:
encoded = text.encode(enc)
print(f"{enc:12s}: {len(encoded):2d} bytes | {encoded.hex()[:40]}...")
# 출력:
# utf-8 : 17 bytes | 48656c6c6f20ed959ceab880f09f9880
# utf-16-le : 20 bytes | 480065006c006c006f002000d55c00aeb800...
# utf-16-be : 20 bytes | 004800650069006c006f0020d55cae00b800...
# utf-32-le : 36 bytes | 4100000065000000...
7. 한글 인코딩 (EUC-KR, CP949)
한글 인코딩 역사
아래 코드는 mermaid를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
timeline
title 한글 인코딩 발전
1987 : KS X 1001\n완성형 2,350자
1992 : EUC-KR\n완성형 표준
1996 : CP949 (MS)\n확장 완성형 11,172자
2000s : UTF-8\nUnicode 기반
EUC-KR
EUC-KR은 2바이트로 한글 2,350자를 표현합니다. 아래 코드는 python를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# EUC-KR 인코딩
text = "한글"
euckr_bytes = text.encode('euc-kr')
print(euckr_bytes.hex()) # c7d1 b1db
# '한': 0xC7D1
# '글': 0xB1DB
# 문제: '똠', '쀍' 같은 글자는 표현 불가
try:
"똠".encode('euc-kr')
except UnicodeEncodeError as e:
print(f"❌ EUC-KR로 인코딩 불가: {e}")
CP949 (확장 완성형)
CP949는 EUC-KR을 확장하여 11,172자 모두 지원합니다. 아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
# CP949 인코딩
text = "똠방각하"
cp949_bytes = text.encode('cp949')
print(cp949_bytes.hex())
# EUC-KR에 없는 글자도 표현 가능
text2 = "쀍똠뙠"
print(text2.encode('cp949').hex())
UTF-8 vs EUC-KR 비교
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
text = "Hello 한글"
# UTF-8: 영문 1바이트, 한글 3바이트
utf8 = text.encode('utf-8')
print(f"UTF-8: {len(utf8)} bytes | {utf8.hex()}")
# UTF-8: 14 bytes | 48656c6c6f20ed959ceab880
# EUC-KR: 영문 1바이트, 한글 2바이트
euckr = text.encode('euc-kr')
print(f"EUC-KR: {len(euckr)} bytes | {euckr.hex()}")
# EUC-KR: 10 bytes | 48656c6c6f20c7d1b1db
8. BOM과 Endian
BOM (Byte Order Mark)
BOM은 파일 시작 부분에 붙는 특수 바이트로, 인코딩 방식과 바이트 순서를 표시합니다. 아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
인코딩 | BOM (hex) | 크기
UTF-8 | EF BB BF | 3바이트
UTF-16 LE | FF FE | 2바이트
UTF-16 BE | FE FF | 2바이트
UTF-32 LE | FF FE 00 00 | 4바이트
UTF-32 BE | 00 00 FE FF | 4바이트
BOM 예시
다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# UTF-8 with BOM
text = "Hello"
with open('file_with_bom.txt', 'wb') as f:
f.write(b'\xef\xbb\xbf') # BOM
f.write(text.encode('utf-8'))
# 파일 내용 (hex):
# EF BB BF 48 65 6C 6C 6F
# ^^^^^^^^ BOM
# ^^^^^^^^^^^^^^ "Hello"
# UTF-8 without BOM (권장)
with open('file_no_bom.txt', 'wb') as f:
f.write(text.encode('utf-8'))
# 파일 내용 (hex):
# 48 65 6C 6C 6F
BOM 감지 및 제거
다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
def detect_and_remove_bom(data):
"""BOM 감지 및 제거"""
bom_signatures = [
(b'\xef\xbb\xbf', 'utf-8-sig'),
(b'\xff\xfe\x00\x00', 'utf-32-le'),
(b'\x00\x00\xfe\xff', 'utf-32-be'),
(b'\xff\xfe', 'utf-16-le'),
(b'\xfe\xff', 'utf-16-be'),
]
for bom, encoding in bom_signatures:
if data.startswith(bom):
return data[len(bom):], encoding
return data, None
# 사용
with open('file.txt', 'rb') as f:
data = f.read()
data, encoding = detect_and_remove_bom(data)
if encoding:
print(f"✅ BOM detected: {encoding}")
text = data.decode(encoding.replace('-sig', '))
else:
print("ℹ️ No BOM, assuming UTF-8")
text = data.decode('utf-8')
Endian (바이트 순서)
다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# Big-Endian: 큰 바이트가 먼저
# Little-Endian: 작은 바이트가 먼저
# 예: 0x1234를 메모리에 저장
# Big-Endian: 12 34
# Little-Endian: 34 12
# UTF-16에서 중요
text = "한" # U+D55C
# UTF-16 BE (Big-Endian)
be = text.encode('utf-16-be')
print(be.hex()) # d5 5c
# UTF-16 LE (Little-Endian)
le = text.encode('utf-16-le')
print(le.hex()) # 5c d5
# UTF-8은 바이트 단위라 Endian 무관
utf8 = text.encode('utf-8')
print(utf8.hex()) # ed 95 9c (항상 같음)
9. 실전 문제 해결
문제 1: 한글 깨짐 (���)
원인
아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
# ❌ UTF-8로 저장했는데 EUC-KR로 읽음
with open('file.txt', 'w', encoding='utf-8') as f:
f.write("한글")
# 잘못된 읽기
with open('file.txt', 'r', encoding='euc-kr') as f:
text = f.read()
print(text) # '���' (깨짐)
해결
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ✅ 올바른 인코딩으로 읽기
with open('file.txt', 'r', encoding='utf-8') as f:
text = f.read()
print(text) # '한글' (정상)
# ✅ 인코딩 자동 감지
import chardet
with open('file.txt', 'rb') as f:
raw_data = f.read()
result = chardet.detect(raw_data)
encoding = result['encoding']
confidence = result['confidence']
print(f"Detected: {encoding} ({confidence*100:.1f}% confidence)")
text = raw_data.decode(encoding)
print(text)
문제 2: UnicodeDecodeError
다음은 python를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ❌ 잘못된 인코딩으로 디코딩
utf8_bytes = "한글".encode('utf-8')
try:
text = utf8_bytes.decode('ascii')
except UnicodeDecodeError as e:
print(f"❌ {e}")
# 'ascii' codec can't decode byte 0xed in position 0
# ✅ 에러 처리 옵션
# 1. 무시
text = utf8_bytes.decode('ascii', errors='ignore')
print(text) # "" (한글 제거됨)
# 2. 대체
text = utf8_bytes.decode('ascii', errors='replace')
print(text) # "������" (? 문자로 대체)
# 3. XML/HTML 엔티티
text = utf8_bytes.decode('ascii', errors='xmlcharrefreplace')
print(text) # "한글" (숫자 참조)
문제 3: 웹에서 한글 깨짐
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import requests
# ❌ 잘못된 방법
response = requests.get('https://example.com/korean-page')
print(response.text) # 깨질 수 있음
# ✅ Content-Type 헤더 확인
response = requests.get('https://example.com/korean-page')
content_type = response.headers.get('Content-Type', ')
print(f"Content-Type: {content_type}")
# Content-Type: text/html; charset=euc-kr
# ✅ 올바른 인코딩으로 디코딩
if 'euc-kr' in content_type.lower():
text = response.content.decode('euc-kr')
else:
text = response.text # requests가 자동 감지
# ✅ 또는 chardet으로 자동 감지
import chardet
detected = chardet.detect(response.content)
text = response.content.decode(detected['encoding'])
문제 4: CSV 파일 인코딩
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import csv
# ❌ Windows Excel에서 저장한 CSV (CP949)
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
print(row) # UnicodeDecodeError!
# ✅ 올바른 인코딩
with open('data.csv', 'r', encoding='cp949') as f:
reader = csv.reader(f)
for row in reader:
print(row)
# ✅ 인코딩 자동 감지
import chardet
with open('data.csv', 'rb') as f:
raw_data = f.read()
detected = chardet.detect(raw_data)
encoding = detected['encoding']
with open('data.csv', 'r', encoding=encoding) as f:
reader = csv.reader(f)
for row in reader:
print(row)
10. 프로그래밍 언어별 처리
Python
다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 기본 인코딩: UTF-8
text = "Hello 한글 😀"
# 인코딩
utf8 = text.encode('utf-8')
utf16 = text.encode('utf-16')
euckr = text.encode('euc-kr') # 이모지는 에러
# 디코딩
text = utf8.decode('utf-8')
# 파일 I/O
with open('file.txt', 'w', encoding='utf-8') as f:
f.write(text)
with open('file.txt', 'r', encoding='utf-8') as f:
text = f.read()
# 바이트 문자열 리터럴
utf8_bytes = b'\xed\x95\x9c\xea\xb8\x80'
text = utf8_bytes.decode('utf-8') # "한글"
JavaScript/Node.js
다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// JavaScript 내부: UTF-16
const text = "Hello 한글 😀";
// 문자열 길이 (주의: 서로게이트 페어)
console.log(text.length); // 11 (😀가 2로 계산됨)
// 올바른 길이
console.log([...text].length); // 10
// UTF-8 인코딩 (Node.js)
const buffer = Buffer.from(text, 'utf-8');
console.log(buffer); // <Buffer 48 65 6c 6c 6f 20 ...>
// 디코딩
const decoded = buffer.toString('utf-8');
console.log(decoded); // "Hello 한글 😀"
// 지원 인코딩
// utf-8, utf-16le, latin1, base64, hex, ascii
Java
다음은 java를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Java 내부: UTF-16
String text = "Hello 한글 😀";
// UTF-8 인코딩
byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(utf8Bytes));
// 디코딩
String decoded = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println(decoded);
// 파일 I/O
// UTF-8로 쓰기
Files.writeString(
Path.of("file.txt"),
text,
StandardCharsets.UTF_8
);
// UTF-8로 읽기
String content = Files.readString(
Path.of("file.txt"),
StandardCharsets.UTF_8
);
C++
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>
#include <locale>
int main() {
// UTF-8 문자열 (C++11)
std::string utf8_str = u8"Hello 한글 😀";
// UTF-16 문자열
std::u16string utf16_str = u"Hello 한글 😀";
// UTF-32 문자열
std::u32string utf32_str = U"Hello 한글 😀";
// UTF-8 → UTF-16 변환
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
std::u16string utf16 = converter.from_bytes(utf8_str);
// 파일 쓰기 (UTF-8)
std::ofstream file("file.txt", std::ios::binary);
file << utf8_str;
file.close();
// 파일 읽기
std::ifstream input("file.txt", std::ios::binary);
std::string content((std::istreambuf_iterator<char>(input)),
std::istreambuf_iterator<char>());
std::cout << content << std::endl;
return 0;
}
Go
다음은 go를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
package main
import (
"fmt"
"unicode/utf8"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/transform"
"io"
"strings"
)
func main() {
// Go 내부: UTF-8
text := "Hello 한글 😀"
// 바이트 길이 vs 문자(rune) 길이
fmt.Println("Bytes:", len(text)) // 17
fmt.Println("Runes:", utf8.RuneCountInString(text)) // 10
// UTF-8 → EUC-KR 변환
encoder := korean.EUCKR.NewEncoder()
euckrBytes, _, _ := transform.Bytes(encoder, []byte(text))
fmt.Printf("EUC-KR: %x\n", euckrBytes)
// EUC-KR → UTF-8 변환
decoder := korean.EUCKR.NewDecoder()
utf8Text, _, _ := transform.String(decoder, string(euckrBytes))
fmt.Println(utf8Text)
}
고급 주제
정규화 (Normalization)
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import unicodedata
# 한글 '가'를 표현하는 두 가지 방법
# 1. 완성형 (NFC): U+AC00
nfc = "가"
print(f"NFC: {len(nfc)} chars, {nfc.encode('utf-8').hex()}")
# NFC: 1 chars, eab080
# 2. 조합형 (NFD): U+1100 + U+1161 (ㄱ + ㅏ)
nfd = unicodedata.normalize('NFD', nfc)
print(f"NFD: {len(nfd)} chars, {nfd.encode('utf-8').hex()}")
# NFD: 2 chars, e384 80e185a1
# 비교
print(nfc == nfd) # False (다른 바이트 시퀀스)
# 정규화 후 비교
print(unicodedata.normalize('NFC', nfc) ==
unicodedata.normalize('NFC', nfd)) # True
인코딩 감지
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import chardet
def detect_encoding(file_path):
"""파일 인코딩 자동 감지"""
with open(file_path, 'rb') as f:
raw_data = f.read()
result = chardet.detect(raw_data)
return {
'encoding': result['encoding'],
'confidence': result['confidence'],
'language': result.get('language', ')
}
# 사용
info = detect_encoding('unknown.txt')
print(f"Encoding: {info['encoding']}")
print(f"Confidence: {info['confidence']*100:.1f}%")
# 올바른 인코딩으로 읽기
with open('unknown.txt', 'r', encoding=info['encoding']) as f:
content = f.read()
인코딩 변환
아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
def convert_file_encoding(input_file, output_file, from_enc, to_enc):
"""파일 인코딩 변환"""
# 원본 읽기
with open(input_file, 'r', encoding=from_enc) as f:
content = f.read()
# 새 인코딩으로 저장
with open(output_file, 'w', encoding=to_enc) as f:
f.write(content)
print(f"✅ Converted: {from_enc} → {to_enc}")
# EUC-KR → UTF-8 변환
convert_file_encoding('old.txt', 'new.txt', 'euc-kr', 'utf-8')
웹 개발에서의 인코딩
HTML
아래 코드는 html를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<!DOCTYPE html>
<html>
<head>
<!-- ✅ UTF-8 선언 (필수) -->
<meta charset="UTF-8">
<title>한글 페이지</title>
</head>
<body>
<h1>안녕하세요</h1>
</body>
</html>
HTTP 헤더
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
from flask import Flask, Response
app = Flask(__name__)
@app.route('/korean')
def korean_page():
content = "<h1>안녕하세요</h1>"
# ✅ Content-Type에 charset 명시
return Response(
content,
mimetype='text/html; charset=utf-8'
)
# ❌ charset 없으면 브라우저가 추측 (깨질 수 있음)
JSON
아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import json
data = {"name": "홍길동", "message": "안녕하세요"}
# JSON은 기본적으로 UTF-8
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)
# {"name": "홍길동", "message": "안녕하세요"}
# ensure_ascii=True (기본값)
json_str_ascii = json.dumps(data, ensure_ascii=True)
print(json_str_ascii)
# {"name": "\ud64d\uae38\ub3d9", "message": "\uc548\ub155\ud558\uc138\uc694"}
URL 인코딩
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
from urllib.parse import quote, unquote
# URL에 한글 포함
text = "한글 검색"
# URL 인코딩 (UTF-8 기반)
encoded = quote(text)
print(encoded)
# %ED%95%9C%EA%B8%80%20%EA%B2%80%EC%83%89
# URL 디코딩
decoded = unquote(encoded)
print(decoded) # "한글 검색"
# 완전한 URL
url = f"https://example.com/search?q={encoded}"
print(url)
# https://example.com/search?q=%ED%95%9C%EA%B8%80%20%EA%B2%80%EC%83%89
데이터베이스 인코딩
MySQL
다음은 sql를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
-- 데이터베이스 생성 (UTF-8)
CREATE DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- utf8mb4: 4바이트 UTF-8 (이모지 지원)
-- utf8: 3바이트 UTF-8 (이모지 미지원, deprecated)
-- 테이블 생성
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100) CHARACTER SET utf8mb4
);
-- 연결 시 인코딩 설정
SET NAMES utf8mb4;
PostgreSQL
아래 코드는 sql를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
-- 데이터베이스 생성
CREATE DATABASE mydb
ENCODING 'UTF8'
LC_COLLATE 'ko_KR.UTF-8'
LC_CTYPE 'ko_KR.UTF-8';
-- 클라이언트 인코딩 확인
SHOW client_encoding;
-- 인코딩 변경
SET client_encoding TO 'UTF8';
Python + DB
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import psycopg2
# PostgreSQL 연결
conn = psycopg2.connect(
host='localhost',
database='mydb',
user='user',
password='pass',
client_encoding='utf8'
)
cursor = conn.cursor()
# 한글 데이터 삽입
cursor.execute(
"INSERT INTO users (name) VALUES (%s)",
("홍길동",)
)
# 조회
cursor.execute("SELECT name FROM users")
name = cursor.fetchone()[0]
print(name) # "홍길동"
실전 도구
명령줄 도구
다음은 bash를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 1. file 명령어로 인코딩 확인
file -i file.txt
# file.txt: text/plain; charset=utf-8
# 2. iconv로 인코딩 변환
iconv -f EUC-KR -t UTF-8 old.txt > new.txt
# 3. 여러 파일 일괄 변환
find . -name "*.txt" -exec iconv -f EUC-KR -t UTF-8 {} -o {}.utf8 \;
# 4. hexdump로 바이트 확인
echo "한글" | hexdump -C
# 00000000 ed 95 9c ea b8 80 0a
# 5. BOM 제거
tail -c +4 file_with_bom.txt > file_no_bom.txt # UTF-8 BOM (3바이트)
Python 스크립트
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#!/usr/bin/env python3
"""
파일 인코딩 일괄 변환 도구
"""
import os
import sys
import chardet
from pathlib import Path
def convert_directory(directory, from_enc=None, to_enc='utf-8'):
"""디렉토리 내 모든 텍스트 파일 인코딩 변환"""
for file_path in Path(directory).rglob('*.txt'):
try:
# 원본 읽기
with open(file_path, 'rb') as f:
raw_data = f.read()
# 인코딩 감지
if from_enc is None:
detected = chardet.detect(raw_data)
source_enc = detected['encoding']
confidence = detected['confidence']
if confidence < 0.7:
print(f"⚠️ {file_path}: Low confidence ({confidence:.2f})")
continue
else:
source_enc = from_enc
# 이미 UTF-8이면 스킵
if source_enc.lower().replace('-', ') == 'utf8':
print(f"✓ {file_path}: Already UTF-8")
continue
# 변환
text = raw_data.decode(source_enc)
# 저장
with open(file_path, 'w', encoding=to_enc) as f:
f.write(text)
print(f"✅ {file_path}: {source_enc} → {to_enc}")
except Exception as e:
print(f"❌ {file_path}: {e}")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python convert_encoding.py <directory>")
sys.exit(1)
convert_directory(sys.argv[1])
인코딩 비교표
저장 공간 비교
text = "Hello 한글 😀"
encodings = {
'ASCII (영문만)': 'ascii',
'UTF-8': 'utf-8',
'UTF-16 LE': 'utf-16-le',
'UTF-16 BE': 'utf-16-be',
'UTF-32 LE': 'utf-32-le',
'EUC-KR': 'euc-kr',
'CP949': 'cp949',
}
print(f"원본 텍스트: {text}\n")
print(f"{'인코딩':15s} | {'바이트':6s} | Hex")
print("-" * 50)
for name, enc in encodings.items():
try:
encoded = text.encode(enc)
hex_str = encoded.hex()[:30] + ('...' if len(encoded) > 15 else ')
print(f"{name:15s} | {len(encoded):4d}B | {hex_str}")
except UnicodeEncodeError:
print(f"{name:15s} | {'N/A':6s} | (인코딩 불가)")
# 출력:
# 원본 텍스트: Hello 한글 😀
#
# 인코딩 | 바이트 | Hex
# --------------------------------------------------
# ASCII (영문만) | N/A | (인코딩 불가)
# UTF-8 | 17B | 48656c6c6f20ed959ceab880f0...
# UTF-16 LE | 20B | 480065006c006c006f00200000...
# UTF-16 BE | 20B | 004800650069006c006f002000...
# UTF-32 LE | 36B | 410000006500000069000000...
# EUC-KR | N/A | (인코딩 불가)
# CP949 | N/A | (인코딩 불가)
특성 비교
| 인코딩 | 바이트/문자 | ASCII 호환 | 한글 효율 | 이모지 | 주요 사용처 |
|---|---|---|---|---|---|
| ASCII | 1 | ✅ | ❌ | ❌ | 영문 전용 |
| EUC-KR | 1-2 | ✅ | ✅✅ | ❌ | 한국 레거시 |
| CP949 | 1-2 | ✅ | ✅✅ | ❌ | Windows 한글 |
| UTF-8 | 1-4 | ✅ | ✅ | ✅ | 웹, Linux, 현대 표준 |
| UTF-16 | 2-4 | ❌ | ✅✅ | ✅ | Windows, Java 내부 |
| UTF-32 | 4 | ❌ | ❌ | ✅ | 내부 처리 |
실전 시나리오
시나리오 1: 레거시 시스템 연동
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 문제: 은행 API가 EUC-KR 응답
import requests
response = requests.get('http://legacy-bank-api.com/account')
# ❌ 자동 디코딩 (UTF-8 가정)
# print(response.text) # 깨짐
# ✅ 올바른 처리
content = response.content # 바이트
text = content.decode('euc-kr')
print(text)
# ✅ 또는 requests에 힌트 제공
response.encoding = 'euc-kr'
print(response.text)
시나리오 2: 다국어 지원 애플리케이션
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import locale
import sys
def setup_encoding():
"""시스템 인코딩 설정"""
# 표준 출력 인코딩 확인
print(f"stdout encoding: {sys.stdout.encoding}")
# 시스템 로케일
print(f"System locale: {locale.getpreferredencoding()}")
# UTF-8 강제 (Python 3.7+)
if sys.stdout.encoding != 'utf-8':
sys.stdout.reconfigure(encoding='utf-8')
# 다국어 텍스트 처리
texts = {
'en': "Hello",
'ko': "안녕하세요",
'ja': "こんにちは",
'zh': "你好",
'ar': "مرحبا",
'ru': "Здравствуйте",
'emoji': "👋🌍"
}
for lang, text in texts.items():
utf8 = text.encode('utf-8')
print(f"{lang:5s}: {text:15s} | {len(utf8):2d} bytes | {utf8.hex()[:30]}")
시나리오 3: 파일 업로드 처리
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
from flask import Flask, request
import chardet
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['file']
# 바이너리로 읽기
content = file.read()
# 인코딩 감지
detected = chardet.detect(content)
encoding = detected['encoding']
confidence = detected['confidence']
print(f"Detected: {encoding} ({confidence*100:.1f}%)")
# UTF-8로 변환
if encoding.lower() != 'utf-8':
try:
text = content.decode(encoding)
utf8_content = text.encode('utf-8')
return {
'status': 'converted',
'from': encoding,
'to': 'utf-8',
'content': text
}
except Exception as e:
return {'status': 'error', 'message': str(e)}, 400
return {
'status': 'ok',
'encoding': 'utf-8',
'content': content.decode('utf-8')
}
베스트 프랙티스
1. 항상 UTF-8 사용
다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ✅ 파일 I/O
with open('file.txt', 'w', encoding='utf-8') as f:
f.write("한글")
# ✅ 소스 코드 인코딩 선언 (Python 2)
# -*- coding: utf-8 -*-
# ✅ HTML
# <meta charset="UTF-8">
# ✅ HTTP 헤더
# Content-Type: text/html; charset=utf-8
# ✅ 데이터베이스
# CREATE DATABASE mydb CHARACTER SET utf8mb4;
2. 바이너리 모드로 읽고 명시적 디코딩
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ✅ 안전한 방법
with open('file.txt', 'rb') as f:
raw_data = f.read()
# 인코딩 확인 후 디코딩
text = raw_data.decode('utf-8')
# ❌ 위험한 방법 (시스템 기본 인코딩 사용)
with open('file.txt', 'r') as f: # encoding 미지정
text = f.read()
3. 에러 처리
다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ✅ 에러 처리 전략
def safe_decode(data, encodings=['utf-8', 'cp949', 'euc-kr', 'latin-1']):
"""여러 인코딩 시도"""
for enc in encodings:
try:
return data.decode(enc), enc
except UnicodeDecodeError:
continue
# 모두 실패하면 에러 무시하고 디코딩
return data.decode('utf-8', errors='replace'), 'utf-8'
# 사용
with open('unknown.txt', 'rb') as f:
data = f.read()
text, encoding = safe_decode(data)
print(f"Decoded as {encoding}: {text}")
4. BOM 처리
아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# ✅ UTF-8 BOM 자동 처리
with open('file.txt', 'r', encoding='utf-8-sig') as f:
text = f.read() # BOM이 있으면 자동 제거
# ✅ BOM 없이 저장 (권장)
with open('file.txt', 'w', encoding='utf-8') as f:
f.write(text)
# ❌ BOM 포함 저장 (피하기)
with open('file.txt', 'w', encoding='utf-8-sig') as f:
f.write(text)
문제 해결 체크리스트
한글이 깨질 때
아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 1. 파일 인코딩 확인
import chardet
with open('file.txt', 'rb') as f:
result = chardet.detect(f.read())
print(result)
# 2. 올바른 인코딩으로 읽기
with open('file.txt', 'r', encoding='cp949') as f:
text = f.read()
# 3. UTF-8로 재저장
with open('file.txt', 'w', encoding='utf-8') as f:
f.write(text)
웹에서 한글이 깨질 때
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 1. HTTP 헤더 확인
import requests
response = requests.get('https://example.com')
print(response.encoding) # ISO-8859-1 (잘못된 추측)
# 2. 올바른 인코딩 설정
response.encoding = 'utf-8'
print(response.text)
# 3. Content-Type 헤더 확인
print(response.headers.get('Content-Type'))
# text/html; charset=euc-kr
# 4. 명시적 디코딩
text = response.content.decode('euc-kr')
데이터베이스에서 한글이 깨질 때
다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 1. 연결 인코딩 확인
import pymysql
conn = pymysql.connect(
host='localhost',
user='user',
password='pass',
database='mydb',
charset='utf8mb4' # ✅ 명시적 지정
)
# 2. 테이블 인코딩 확인
cursor = conn.cursor()
cursor.execute("SHOW CREATE TABLE users")
print(cursor.fetchone())
# 3. 인코딩 변환
# ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4;
정리
인코딩 선택 가이드
아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
flowchart TD
Start[새 프로젝트 시작] --> Q1{언어는?}
Q1 -->|영문만| ASCII["ASCII\n또는 UTF-8"]
Q1 -->|다국어| UTF8["✅ UTF-8\n권장"]
Q1 -->|레거시 연동| Q2{시스템은?}
Q2 -->|Windows 한글| CP949[CP949]
Q2 -->|Unix 한글| EUCKR[EUC-KR]
Q2 -->|일본어| SJIS[Shift-JIS]
UTF8 --> Best["✅ 최선의 선택\n- 웹 표준\n- 모든 문자 지원\n- ASCII 호환"]
핵심 원칙
다음은 python를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
# 1. 항상 UTF-8 사용
encoding = 'utf-8'
# 2. 인코딩 명시
with open('file.txt', 'w', encoding='utf-8') as f:
f.write(text)
# 3. 바이너리 모드 + 명시적 디코딩
with open('file.txt', 'rb') as f:
data = f.read()
text = data.decode('utf-8')
# 4. 에러 처리
try:
text = data.decode('utf-8')
except UnicodeDecodeError:
text = data.decode('utf-8', errors='replace')
# 5. 테스트
assert "한글 😀".encode('utf-8').decode('utf-8') == "한글 😀"
인코딩별 요약
| 인코딩 | 바이트 | 장점 | 단점 | 사용 시기 |
|---|---|---|---|---|
| UTF-8 | 1-4 | 웹 표준, ASCII 호환 | 한글 3바이트 | 모든 새 프로젝트 |
| UTF-16 | 2-4 | 한글 2바이트 | ASCII 비호환 | Windows/Java 내부 |
| UTF-32 | 4 | 고정 길이 | 공간 낭비 | 내부 처리 |
| EUC-KR | 1-2 | 한글 2바이트 | 일부 한글 미지원 | 레거시 시스템 |
| CP949 | 1-2 | 모든 한글 지원 | Windows 전용 | Windows 한글 |
디버깅 도구
Python 인코딩 디버거
다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
def analyze_encoding(file_path):
"""파일 인코딩 상세 분석"""
with open(file_path, 'rb') as f:
raw_data = f.read()
print(f"📄 파일: {file_path}")
print(f"📊 크기: {len(raw_data)} bytes\n")
# BOM 확인
if raw_data.startswith(b'\xef\xbb\xbf'):
print("🔖 BOM: UTF-8")
elif raw_data.startswith(b'\xff\xfe'):
print("🔖 BOM: UTF-16 LE")
elif raw_data.startswith(b'\xfe\xff'):
print("🔖 BOM: UTF-16 BE")
else:
print("🔖 BOM: None")
# 인코딩 감지
detected = chardet.detect(raw_data)
print(f"\n🔍 감지된 인코딩: {detected['encoding']}")
print(f"📈 신뢰도: {detected['confidence']*100:.1f}%")
# 여러 인코딩으로 시도
print("\n🧪 디코딩 테스트:")
encodings = ['utf-8', 'cp949', 'euc-kr', 'utf-16', 'latin-1']
for enc in encodings:
try:
text = raw_data.decode(enc)
preview = text[:50].replace('\n', '\\n')
print(f" ✅ {enc:10s}: {preview}")
except UnicodeDecodeError as e:
print(f" ❌ {enc:10s}: {e}")
# Hex dump (처음 100바이트)
print(f"\n🔢 Hex Dump (first 100 bytes):")
for i in range(0, min(100, len(raw_data)), 16):
hex_str = ' '.join(f'{b:02x}' for b in raw_data[i:i+16])
ascii_str = '.join(chr(b) if 32 <= b < 127 else '.' for b in raw_data[i:i+16])
print(f" {i:04x}: {hex_str:48s} | {ascii_str}")
# 사용
analyze_encoding('mystery.txt')
참고 자료
- Unicode Standard
- UTF-8 Specification (RFC 3629)
- Character Encoding in Python
- The Absolute Minimum Every Software Developer Must Know About Unicode 한 줄 요약: 모든 새 프로젝트는 UTF-8을 사용하고, 레거시 시스템 연동 시에만 EUC-KR/CP949를 고려하며, 항상 인코딩을 명시적으로 지정하여 한글 깨짐 문제를 예방하세요.