문자열의 인코딩은 끊어질 때만 생각합니다. 예외 추적기를 확인하고 볼 때
Encoding::InvalidByteSequenceError: "\xFE" on UTF-8
당신의 얼굴을 쳐다보고 있습니다. 또는 "그들이"가 "그들이"로 나타나기 시작할 수도 있습니다.
인코딩이 잘못되었을 때 무엇이 고장났는지 어떻게 알 수 있습니까? 어떻게 고칠 수 있습니까?
인코딩이란 무엇입니까?
인코딩이 문자열에 대해 수행하는 작업을 상상할 수 있다면 이러한 버그를 수정하기가 더 쉽습니다.
문자열을 바이트 배열 또는 작은 숫자로 생각할 수 있습니다.
irb(main):001:0> "hello!".bytes
=> [104, 101, 108, 108, 111, 33]
이 인코딩에서 104
h
를 의미합니다. , 33
!
를 의미합니다. 등이 있습니다.
영어에서 덜 일반적으로 사용되는 문자를 사용하면 더 까다로워집니다.
irb(main):002:0> "hellṏ!".bytes
=> [104, 101, 108, 108, 225, 185, 143, 33]
이제 어떤 숫자가 어떤 문자를 나타내는지 말하기가 더 어렵습니다. 1바이트 대신 ṏ
바이트 그룹으로 표시됩니다. [225, 185, 143]
. 그러나 바이트와 문자 사이에는 여전히 관계가 있습니다. 문자열의 인코딩이 해당 관계를 정의합니다.
다른 인코딩을 시도할 때 단일 바이트 집합이 어떻게 보이는지 살펴보세요.
# Try an ISO-8859-1 string with a special character!
irb(main):003:0> str = "hellÔ!".encode("ISO-8859-1"); str.encode("UTF-8")
=> "hellÔ!"
irb(main):004:0> str.bytes
=> [104, 101, 108, 108, 212, 33]
# What would that string look like interpreted as ISO-8859-5 instead?
irb(main):005:0> str.force_encoding("ISO-8859-5"); str.encode("UTF-8")
=> "hellд!"
irb(main):006:0> str.bytes
=> [104, 101, 108, 108, 212, 33]
바이트는 변경되지 않았습니다. 그러나 그것은 전혀 옳지 않아 보입니다. 인코딩을 변경하면 바이트를 변경하지 않고 문자열이 인쇄되는 방식이 변경되었습니다.
모든 문자열을 모든 인코딩으로 표현할 수 있는 것은 아닙니다. :
irb(main):006:0> "hi∑".encode("Windows-1252")
Encoding::UndefinedConversionError: U+2211 to WINDOWS-1252 in conversion from UTF-8 to WINDOWS-1252
from (irb):61:in `encode'
from (irb):61
from /usr/local/bin/irb:11:in `<main>'
대부분의 인코딩은 작고 가능한 모든 문자를 처리할 수 없습니다. 한 인코딩의 문자가 다른 인코딩에 존재하지 않거나 Ruby가 두 인코딩 간에 문자를 변환하는 방법을 알 수 없을 때 해당 오류가 표시됩니다.
encode
에 추가 옵션을 전달하면 이 오류를 해결할 수 있습니다. :
irb(main):064:0> "hi∑".encode("Windows-1252", invalid: :replace, undef: :replace)
=> "hi?"
invalid
및 undef
옵션은 번역할 수 없는 문자를 다른 문자로 바꿉니다. 기본적으로 대체 문자는 ?
입니다. . (유니코드로 변환하면 �)입니다.
안타깝게도 문자를 encode
로 바꾸면 , 정보를 잃을 수 있습니다. 어떤 바이트가 ?
. 그러나 데이터를 새로운 인코딩으로 사용해야 하는 경우 데이터가 손상되는 것보다 손실이 더 나을 수 있습니다.
지금까지 인코딩을 이해하는 데 도움이 되는 세 가지 주요 문자열 메서드를 살펴보았습니다.
-
encode
, 문자열을 다른 인코딩으로 변환합니다(문자를 새 인코딩에서 해당 문자로 변환) -
bytes
, 문자열을 구성하는 바이트를 표시합니다. -
force_encoding
, 다른 인코딩으로 해석된 바이트의 모양을 보여줍니다.
encode
의 주요 차이점 및 force_encoding
encode
입니까? bytes
를 변경할 수 있음 및 force_encoding
안 됩니다.
인코딩 버그 수정을 위한 3단계 프로세스
다음 세 단계를 통해 대부분의 인코딩 문제를 해결할 수 있습니다.
1. 문자열이 실제로 어떤 인코딩인지 알아보세요. 안으로.
이것은 쉽게 들립니다. 하지만 문자열이 말하기 때문에 일부 인코딩일 뿐 실제로 다음과 같은 의미는 아닙니다.
irb(main):078:0> "hi\x99!".encoding
=> #<Encoding:UTF-8>
그것은 옳지 않습니다 – 그것이 정말이라면 UTF-8에서는 이상한 백슬래시 번호가 없습니다. 그렇다면 문자열에 대한 올바른 인코딩을 어떻게 알 수 있습니까?
많은 구형 소프트웨어는 단일 기본 인코딩을 고수하므로 입력이 어디에서 왔는지 조사할 수 있습니다. 누군가 Word에서 붙여넣었나요? Windows-1252일 수 있습니다. 파일에서 가져왔습니까 아니면 이전 웹 사이트에서 가져왔습니까? ISO-8859-1일 수 있습니다.
또한 연결된 Wikipedia 페이지에 있는 것과 같은 인코딩 테이블을 검색하는 것이 도움이 된다는 것을 알았습니다. 해당 테이블에서 알 수 없는 숫자가 참조하는 문자를 찾아 문맥상 의미가 있는지 확인할 수 있습니다.
이 예에서 Windows-1252 차트는 99
바이트가 "™" 문자를 나타냅니다. 바이트 99
ISO-8859-1에는 존재하지 않습니다. 여기서 ™이 의미가 있는 경우 입력이 Windows-1252에 있다고 가정하고 계속 진행할 수 있습니다. 그렇지 않으면 더 합리적으로 보이는 캐릭터를 찾을 때까지 계속 연구할 수 있습니다.
2. 원하는 인코딩 결정 문자열입니다.
이것은 쉽습니다. 정말 좋은 이유가 없는 한 문자열을 UTF-8로 인코딩하기를 원합니다.
Ruby에서 사용할 수 있는 또 다른 일반적인 인코딩이 있습니다:ASCII-8BIT. ASCII-8BIT에서 모든 문자는 단일 바이트로 표시됩니다. 즉, str.chars.length == str.bytes.length
. 따라서 문자열의 특정 바이트를 많이 제어하려면 ASCII-8BIT가 좋은 옵션일 수 있습니다.
3. 1단계의 인코딩에서 2단계의 인코딩으로 문자열을 다시 인코딩합니다.
encode
로 이 작업을 수행할 수 있습니다. 방법. 이 예에서 문자열은 이었다 Windows-1252 인코딩으로, 우리는 원하는 UTF-8이 됩니다. 매우 간단합니다.
irb(main):088:0> "hi\x99!".encode("UTF-8", "Windows-1252")
=> "hi™!"
훨씬 낫다. (비록 그 호출의 인코딩 순서가 항상 나에게 역순으로 보였지만).
동일한 바이트 배열에 대해 다른 해석을 상상하는 것은 머리가 복잡할 수 있습니다. 특히 그 해석 중 하나가 깨졌을 때. 하지만 인코딩에 훨씬 더 익숙해지는 좋은 방법이 있습니다. 인코딩을 사용하는 것입니다.
irb
열기 콘솔을 사용하고 encode
, bytes
및 force_encoding
. encode
방법 보기 문자열을 구성하는 바이트를 변경합니다. 다른 인코딩이 어떻게 생겼는지 직관을 구축하십시오. 인코딩에 더 익숙해지고 이 단계를 사용하면 몇 시간이 걸리던 작업을 몇 분 안에 해결할 수 있습니다.
마지막으로, 이러한 종류의 학습에서 습관을 만드는 방법을 배우고 싶다면 내 책의 무료 샘플 장을 가져오세요. 콘솔에서 깨는 것은 정말 이와 같은 아이디어를 연구하는 재미있는 방법입니다.