문자열 인코딩은 컴퓨터가 텍스트를 처리하는 방식의 핵심입니다.
인코딩의 기본 원리
- 컴퓨터와 바이트: 컴퓨터는 오직 비트(바이트)만을 이해하며, 텍스트는 바이트로 변환되어 저장되거나 전송됩니다.
- 인코딩의 역할: 바이트와 텍스트 문자 간의 매핑을 인코딩이라고 합니다.
- ASCII의 한계: 초기 ASCII는 7비트로 128개 문자만 표현 가능했으며, 8비트 확장(코드 페이지)은 상호 호환되지 않아 혼란을 야기했습니다.
- 유니코드의 등장: 인터넷 시대에 다양한 언어를 지원하기 위해 유니코드 표준이 등장했습니다. 유니코드는 각 문자에 고유한 코드 포인트(Code Point)를 할당하는 문자 집합(Character Set)입니다.
- UTF-8: 유니코드의 대표적인 가변 길이 인코딩(1~4바이트)으로, ASCII와 호환되며 오류 감지 기능이 내장되어 있습니다.
Ruby의 문자열 인코딩 처리
- 인코딩 정보 저장: Ruby는 다른 언어(JavaScript, Java, C# 등)와 달리 문자열 데이터(바이트)와 해당 인코딩 정보를 함께 저장합니다.
- 유용한 Ruby 메서드:
String#encoding
: 문자열의 현재 인코딩을 확인합니다.String#encode
: 실제 바이트를 변환하여 인코딩을 변경합니다.String#force_encoding
: 바이트는 그대로 두고 문자열에 할당된 인코딩 정보만 변경합니다.String#scrub
: 유효하지 않은 바이트 시퀀스를 대체합니다.String#valid_encoding?
: 인코딩의 유효성을 검사합니다.String#bytesize
: 문자열의 바이트 길이를 반환합니다.String#unicode_normalize
: 문자열의 정규화 형태를 변경하여 동등성을 확인합니다.
실제 인코딩 버그 사례
Socket.gethostname
문제:ASCII-8BIT
(바이너리)로 반환된 호스트 이름이 데이터베이스 저장 시UTF-8
변환 오류를 발생시켰습니다.force_encoding('UTF-8')
을 통해 해결했습니다.ASCII-8BIT
는 인코딩이 알려지지 않은 바이너리 데이터를 의미합니다.- 미스터리한 상위 서러게이트(High Surrogate):
UTF-8
문자열 내에UTF-16
의 상위 서러게이트 코드 포인트가 포함되어 유효하지 않은 바이트 시퀀스 오류가 발생했습니다. 해당 문자를scrub
하여 해결했습니다. - 정규화 형태(Normalization Forms) 불일치: 시각적으로 동일해 보이는 문자열이 다른 유니코드 코드 포인트를 사용하여
URI
정규화 과정에서 문제가 발생했습니다.String#unicode_normalize
를 통해 문자열의 정규화 형태를 일치시켜 해결했습니다.