MacRoman, CP1252, Latin1, UTF-8 및 ASCII 간의 인코딩을 안정적으로 추측하는 방법


99

직장에서 인코딩 관련 연결, 재난 또는 재앙 없이는 일주일이 지나지 않는 것처럼 보입니다. 문제는 일반적으로 인코딩을 지정하지 않고도 "텍스트"파일을 안정적으로 처리 할 수 ​​있다고 생각하는 프로그래머에게서 발생합니다. 그러나 당신은 할 수 없습니다.

따라서 이후에는 파일 이름이 *.txt또는로 끝나는 것을 금지하기로 결정되었습니다 *.text. 이러한 확장은 평범한 프로그래머를 인코딩과 관련하여 지루한 안주로 오도하여 부적절한 처리로 이어진다는 생각입니다. 연장이 전혀없는 것이 거의 낫습니다. 적어도 당신이 가지고있는 것을 모른다는 것을 알고 있기 때문 입니다.

그러나 우리는 그렇게 멀리 갈 수 없습니다. 대신 인코딩으로 끝나는 파일 이름을 사용해야합니다. 텍스트 파일 그래서, 예를 들어, 다음은 같은 것 README.ascii, README.latin1, README.utf8, 등

특정 확장자가 필요한 파일의 경우 Perl 또는 Python과 같이 파일 자체 내부에 인코딩을 지정할 수 있다면 그렇게해야합니다. 파일 내부에 이러한 기능이없는 Java 소스와 같은 파일의 경우 확장자 앞에 인코딩을 넣습니다 (예 : SomeClass-utf8.java.

출력의 경우 UTF-8이 강력하게 선호됩니다.

그러나 입력을 위해 코드베이스에있는 수천 개의 파일을 처리하는 방법을 알아 내야합니다 *.txt. 우리는 새로운 표준에 맞게 모든 이름을 변경하려고합니다. 그러나 우리는 그들 모두를 주시 할 수는 없습니다. 그래서 실제로 작동하는 라이브러리 나 프로그램이 필요합니다.

이들은 ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 또는 Apple MacRoman으로 다양합니다. 우리는 어떤 것이 ASCII인지 알 수 있고 어떤 것이 아마도 UTF-8인지 알 수 있다는 것을 알고 있지만 우리는 8 비트 인코딩에 대해 난처합니다. 대부분의 데스크톱이 Mac 인 혼합 Unix 환경 (Solaris, Linux, Darwin)에서 실행 중이기 때문에 성가신 MacRoman 파일이 꽤 많습니다. 그리고 이것들은 특히 문제입니다.

한동안 저는 프로그래밍 방식으로 다음 중 어떤 것을 결정할 수있는 방법을 찾고있었습니다.

  1. ASCII
  2. ISO-8859-1
  3. CP1252
  4. MacRoman
  5. UTF-8

파일이 있고 세 가지 8 비트 인코딩을 확실하게 구분할 수있는 프로그램이나 라이브러리를 찾지 못했습니다. 우리는 아마도 천 개가 넘는 MacRoman 파일을 가지고있을 것입니다. 그래서 우리가 사용하는 문자셋 탐지기가 무엇이든간에 그것들을 알아낼 수 있어야합니다. 내가 본 어떤 것도 트릭을 관리 할 수 ​​없습니다. ICU charset detector library에 대한 큰 희망이 있었지만 MacRoman을 처리 할 수 ​​없습니다. 또한 Perl과 Python 모두에서 동일한 종류의 작업을 수행하는 모듈을 살펴 보았습니다.하지만 계속해서 동일한 이야기입니다. MacRoman 감지를 지원하지 않습니다.

따라서 내가 찾고있는 것은 파일이 포함 된 5 가지 인코딩 중 어떤 인코딩이 포함되어 있는지, 그리고 바람직하게는 그보다 더 많은 인코딩을 안정적으로 결정하는 기존 라이브러리 또는 프로그램입니다. 특히 내가 인용 한 3 비트 인코딩, 특히 MacRoman 을 구별해야합니다 . 파일은 99 % 이상의 영어 텍스트입니다. 다른 언어로는 적지 만 많지는 않습니다.

라이브러리 코드 인 경우 언어 기본 설정은 Perl, C, Java 또는 Python이고 그 순서입니다. 그것이 단지 프로그램이라면, 우리는 그것이 완전한 소스로 나오고, 유닉스에서 실행되고, 완전히 방해받지 않는 한 그것이 어떤 언어인지는 정말로 신경 쓰지 않습니다.

무작위로 인코딩 된 수많은 레거시 텍스트 파일의 문제가있는 사람이 있습니까? 그렇다면 어떻게 해결하려고했으며 얼마나 성공적 이었습니까? 이것이 내 질문의 가장 중요한 측면이지만, 프로그래머가 파일이있는 실제 인코딩으로 파일의 이름을 지정 (또는 이름 변경)하도록 권장하는 것이 향후 문제를 피하는 데 도움이 될지 여부에 대해서도 관심이 있습니다. 누구도 제도적으로이를 시행했는데, 그렇다면이었다했습니다 이유는 성공 여부, 그리고?

그리고 예, 저는 문제의 본질을 고려할 때 명확한 답변을 보장 할 수없는 이유를 완전히 이해합니다. 데이터가 충분하지 않은 작은 파일의 경우 특히 그렇습니다. 다행히도 파일은 거의 작지 않습니다. 임의 README파일을 제외하고 대부분은 50k에서 250k 사이의 크기 범위에 있으며 대부분은 더 큽니다. 몇 K 이상의 크기는 영어로 보장됩니다.

문제 영역은 생의학 텍스트 마이닝이므로 PubMedCentral의 모든 Open Access 저장소와 같이 광범위하고 매우 큰 말뭉치를 처리하는 경우가 있습니다. 다소 큰 파일은 5.7GB의 BioThesaurus 6.0입니다. 이 파일은 거의 모든 UTF-8 이기 때문에 특히 성가시다 . 그러나 일부 numbskull은 8 비트 인코딩 인 Microsoft CP1252로 된 몇 줄을 삽입했습니다. 당신이 그것을 여행하기까지 꽤 시간이 걸립니다. :(


답변:


86

첫째, 쉬운 경우 :

ASCII

데이터에 0x7F보다 큰 바이트가 없으면 ASCII입니다. (또는 7 비트 ISO646 인코딩이지만 매우 구식입니다.)

UTF-8

데이터의 유효성을 검사가 UTF-8로, 당신은 안전하게 가정 할 경우가 있다 UTF-8. UTF-8의 엄격한 유효성 검사 규칙으로 인해 오탐은 극히 드뭅니다.

ISO-8859-1 대 windows-1252

이 두 인코딩의 유일한 차이점은 ISO-8859-1에는 C1 제어 문자가 있고 windows-1252에는 인쇄 가능한 문자 € ‚ƒ „… † ‡ ˆ ‰ Š‹ŒŽ ''“”• –—˜ ™ š›가 있습니다. œžŸ. 곱슬 따옴표 또는 대시를 사용하는 파일을 많이 보았지만 C1 제어 문자를 사용하는 파일은 없습니다. 따라서 그들 또는 ISO-8859-1에 신경 쓰지 말고 대신 windows-1252를 감지하십시오.

이제 한 가지 질문 만 남았습니다.

MacRoman과 cp1252를 어떻게 구별합니까?

이것은 훨씬 더 까다 롭습니다.

정의되지 않은 문자

0x81, 0x8D, 0x8F, 0x90, 0x9D 바이트는 windows-1252에서 사용되지 않습니다. 발생하면 데이터가 MacRoman이라고 가정합니다.

동일한 문자

바이트 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ)는 두 인코딩 모두에서 동일합니다. 이것이 유일한 비 ASCII 바이트라면 MacRoman을 선택하든 cp1252를 선택하든 상관 없습니다.

통계적 접근

UTF-8로 알고있는 데이터에서 문자 (바이트가 아닙니다!) 주파수를 계산합니다. 가장 빈번한 문자를 결정하십시오. 그런 다음이 데이터를 사용하여 cp1252 또는 MacRoman 문자가 더 일반적인 것인지 확인합니다.

예를 들어 100 개의 임의의 영어 위키 백과 기사에 대해 방금 수행 한 검색에서 가장 일반적인 비 ASCII 문자는 ·•–é°®’èö—. 이 사실을 바탕으로

  • 바이트 0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9 또는 0xF6은 windows-1252를 제안합니다.
  • 바이트 0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5 또는 0xE1은 MacRoman을 제안합니다.

cp1252 제안 바이트와 MacRoman 제안 바이트를 계산하고 가장 큰 바이트를 사용합니다.


6
더 나은 사람이 없었기 때문에 대답을 받아 들였습니다. 그리고 당신은 제가 고쳐 왔던 바로 그 문제들을 잘 작성했습니다. 나는 실제로 그 바이트를 스니핑하는 프로그램이 있지만 내가 생각해 낸 숫자의 약 두 배가 있습니다.
tchrist 2011

10
마침내 이것을 구현했습니다. Wikipedia는 좋은 훈련 데이터가 아닙니다. LANGUAGES 섹션을 포함하지 않는 1k 임의의 en.wikipedia 기사에서 50k unASCII 코드 포인트를 얻었지만 배포는 신뢰할 수 없습니다. 가운데 점과 글 머리 기호가 너무 높습니다. & c & c & c. 그래서 저는 + 14M unASCII 코드 포인트를 채굴하는 모든 UTF8 PubMed Open Access 코퍼스를 사용했습니다. 나는 이것들을 사용하여 모든 8 비트 인코딩의 상대 주파수 모델을 구축합니다. 당신의 것보다 더 멋지지만 그 아이디어를 기반으로합니다. 이것은 표적 도메인 인 생물 의학 텍스트의 인코딩을 매우 예측할 수 있음을 증명 합니다. 나는 이것을 출판해야한다. 감사!
tchrist

5
아직 MacRoman 파일이 없지만 줄 구분 기호로 CR을 사용하면 유용한 테스트를 제공하지 않습니다. 이것은 OS9에 대해 모르지만 이전 버전의 Mac OS에서 작동합니다.
Milliways

10

Mozilla nsUniversalDetector (Perl 바인딩 : Encode :: Detect / Encode :: Detect :: Detector )는 백만 배 검증되었습니다.


더 많은 문서는 여기에서 찾을 수 있습니다 : mozilla.org/projects/intl/detectorsrc.html , 거기에서 문서를 파헤쳐 보면 지원되는 문자 세트를 찾을 수 있다고 제안합니다
Joel Berger

@Joel : 소스를 파헤 쳤습니다. 수사 학적 질문이었습니다. x-mac-cyrillic지원 x-mac-hebrew되고, 주석에서 길게 논의되며 x-mac-anything-else, 언급이 없습니다.
John Machin

@John Machin : 키릴 어와 히브리어가 고개를 끄덕이는 것이 이상하지만 다른 것은 없습니다. 나는 다른 문서 소스에만 던지고 있었고 더 이상 읽지 않았습니다. 그렇게 해 주셔서 감사합니다!
Joel Berger

7

그러한 휴리스틱 시도 (ASCII와 UTF-8을 배제했다고 가정) :

  • 0x7f ~ 0x9f가 전혀 나타나지 않으면 거의 사용되지 않는 제어 코드이므로 ISO-8859-1 일 가능성이 높습니다.
  • 0x91에서 0x94까지 많이 나타나면 Windows-1252 일 가능성이 높습니다. 이는 "똑똑한 따옴표"이므로 해당 범위에서 영어 텍스트에 사용될 가능성이 가장 높은 문자입니다. 더 확실히하기 위해 쌍을 찾을 수 있습니다.
  • 그렇지 않으면 MacRoman입니다. 특히 0xd2에서 0xd5까지 많이 표시되는 경우 (MacRoman에서 인쇄용 따옴표가있는 곳입니다).

참고 :

파일 내부에 이러한 기능이없는 Java 소스와 같은 파일의 경우 SomeClass-utf8.java와 같이 확장자 앞에 인코딩을 넣습니다.

이러지마 !!

Java 컴파일러는 파일 이름이 클래스 이름과 일치 할 것으로 예상하므로 파일 이름을 바꾸면 소스 코드를 컴파일 할 수 없게됩니다. 올바른 방법은 인코딩을 추측 한 다음 native2ascii도구를 사용하여 모든 비 ASCII 문자를 유니 코드 이스케이프 시퀀스 로 변환하는 것 입니다.


7
Stoopid kompilor! 아니요, 우리는 사람들에게 ASCII 만 사용할 수 있다고 말할 수 없습니다. 이것은 더 이상 1960 년대가 아닙니다. @encoding 어노테이션이있어 소스가 특정 인코딩에 있다는 사실이 소스 코드 외부에 저장되지 않도록하는 것은 문제가되지 않습니다. 이는 Perl이나 Python이 겪지 않는 Java의 정말 멍청한 단점입니다. . 소스에 있어야합니다. 그러나 그것은 우리의 주요 문제가 아닙니다. 수천 개의 *.text파일입니다.
tchrist 2011

3
@tchrist : 실제로 그러한 주석을 지원하기 위해 자체 주석 프로세서를 작성하는 것은 그리 어렵지 않습니다. 표준 API에 포함되지 않는 것은 여전히 ​​당황스러운 감독입니다.
Michael Borgwardt

Java가 @encoding을 지원하더라도 인코딩 선언이 올바른지 보장 할 수 없습니다 .
dan04 2010

4
@ dan04 : XML, HTML 또는 다른 곳에서 인코딩 선언에 대해 동일하게 말할 수 있습니다. 그러나 이러한 예제와 마찬가지로 표준 API에 정의 된 경우 소스 코드와 함께 작동하는 대부분의 도구 (특히 편집기 및 IDE)가이를 지원하므로 사람들 이 콘텐츠의 인코딩이 일치하지 않는 파일 을 실수로 생성 하는 것을 매우 안정적으로 방지 할 수 있습니다. 선언.
Michael Borgwardt

4
"Java 컴파일러는 파일 이름이 클래스 이름과 일치 할 것으로 예상합니다." 이 규칙은 파일이 최상위 공용 클래스를 정의하는 경우에만 적용됩니다.
Matthew Flaschen

6

"Perl, C, Java 또는 Python, 그리고 그 순서": 흥미로운 태도 :-)

"우리는 어떤 것이 아마도 UTF-8인지 아는 좋은 변화를 가지고 있습니다.": 실제로는 높은 비트 세트 바이트를 사용하는 다른 문자 세트로 인코딩 된 의미있는 텍스트를 포함하는 파일이 UTF-8이 매우 작기 때문에 성공적으로 디코딩 될 가능성이 있습니다.

UTF-8 전략 (최소 선호 언어) :

# 100% Unicode-standard-compliant UTF-8
def utf8_strict(text):
    try:
        text.decode('utf8')
        return True
    except UnicodeDecodeError:
        return False

# looking for almost all UTF-8 with some junk
def utf8_replace(text):
    utext = text.decode('utf8', 'replace')
    dodgy_count = utext.count(u'\uFFFD') 
    return dodgy_count, utext
    # further action depends on how large dodgy_count / float(len(utext)) is

# checking for UTF-8 structure but non-compliant
# e.g. encoded surrogates, not minimal length, more than 4 bytes:
# Can be done with a regex, if you need it

ASCII도 UTF-8도 아니라고 결정한 후 :

내가 아는 Mozilla-origin charset detectors는 MacRoman을 지원하지 않으며 어떤 경우에도 AFAICT가 주어진 디코딩이 의미가 있는지 확인하는 데 의존하기 때문에 특히 영어를 사용하는 8 비트 문자 세트에서 좋은 작업을 수행하지 않습니다. 구두점 문자를 무시하고 해당 언어로 된 다양한 문서를 기반으로합니다.

다른 사람들이 언급했듯이 cp1252와 macroman을 구별하는 데 사용할 수있는 높은 비트 세트 구두점 문자 만 있습니다. 셰익스피어, 한사드 또는 KJV 성경이 아닌 자신의 문서에서 모질라 유형 모델을 훈련하고 256 바이트를 모두 고려하는 것이 좋습니다. 파일에 마크 업 (HTML, XML 등)이 없다고 가정합니다. 이로 인해 확률이 충격적인 것으로 왜곡됩니다.

대부분 UTF-8이지만 디코딩에 실패한 파일을 언급하셨습니다. 또한 다음 사항을 매우 의심해야합니다.

(1) ISO-8859-1로 인코딩 된 것으로 추정되지만 0x80에서 0x9F 범위의 "제어 문자"를 포함하는 파일 ... 이것은 HTML5 표준 초안 에서 ISO-8859로 선언 된 모든 HTML 스트림 을 디코딩하도록 명시하고 있습니다. -1 cp1252 사용.

(2) UTF-8로 OK를 디코딩하지만 결과 유니 코드에는 U + 0080에서 U + 009F까지 범위의 "제어 문자"가 포함되어있는 파일 ... 이는 cp1252 / cp850 (발생 함!) / 등을 트랜스 코딩하여 발생할 수 있습니다. "ISO-8859-1"에서 UTF-8로 파일.

배경 : 저는 (웹 지향이 아닌) 파일 지향적이고 legacy ** ncp850 및 cp437과 같은 것을 포함하여 8 비트 문자 세트와 잘 작동하는 Python 기반 문자 세트 감지기를 만드는 습식 일요일 오후 프로젝트가 있습니다 . 아직 황금 시간대가 아닙니다. 교육 파일에 관심이 있습니다. ISO-8859-1 / cp1252 / MacRoman 파일이 다른 사람의 코드 솔루션이 될 것으로 예상하는 것과 똑같이 "제한되지"않습니까?


1
언어 순서의 이유는 환경입니다. 대부분의 주요 응용 프로그램은 Java에 있고 부 유틸리티와 일부 응용 프로그램은 펄에 있습니다. 여기 저기 파이썬에있는 약간의 코드가 있습니다. 저는 대부분 C 및 Perl 프로그래머이며 적어도 첫 번째 선택에 따라 앱 라이브러리에 연결할 자바 솔루션을 찾고 있었거나 동일한 것을위한 perl 라이브러리를 찾고있었습니다. C 인 경우 XS 글루 레이어를 만들어 perl 인터페이스에 연결할 수 있지만 이전에는 Python에서이를 수행 한 적이 없습니다.
tchrist

3

이미 알고 있듯이이 문제를 해결하는 완벽한 방법은 없습니다. 파일이 사용하는 인코딩에 대한 암시 적 지식이 없으면 모든 8 비트 인코딩이 정확히 동일합니다. 바이트 모음입니다. 모든 바이트는 모든 8 비트 인코딩에 유효합니다.

당신이 기대할 수있는 최선의 방법은 바이트를 분석하는 일종의 알고리즘이며, 특정 인코딩을 사용하여 특정 언어에서 사용되는 특정 바이트의 확률에 따라 파일이 사용하는 인코딩을 추측합니다. 그러나 파일이 사용하는 언어를 알아야하며 인코딩이 혼합 된 파일이 있으면 완전히 쓸모 없게됩니다.

한편, 파일의 텍스트가 영어로 작성되었다는 것을 안다면, 언급 된 모든 인코딩 간의 차이가 모두 현지화되어 있으므로 해당 파일에 사용하기로 결정한 인코딩의 차이를 눈치 채지 못할 것입니다. 일반적으로 영어에서 사용되지 않는 문자를 지정하는 인코딩 부분. 텍스트가 특수 서식 또는 특수 버전의 구두점 (예 : CP1252에는 여러 버전의 따옴표 문자가 있음)을 사용하는 몇 가지 문제가있을 수 있지만 텍스트의 요점에는 문제가 없을 것입니다.


1

macroman을 제외한 모든 인코딩을 감지 할 수 있다면 해독 할 수없는 인코딩이 macroman에 있다고 가정하는 것이 논리적입니다. 즉, 처리 할 수없는 파일 목록을 만들어 마치 매크로 맨 인 것처럼 처리하면됩니다.

이러한 파일을 정렬하는 또 다른 방법은 사용자가 어떤 인코딩이 깨지지 않는지 결정할 수있는 서버 기반 프로그램을 만드는 것입니다. 물론 회사 내부에있을 것이지만 100 명의 직원이 매일 몇 번씩 작업을 수행하면 수천 개의 파일을 즉시 처리 할 수 ​​있습니다.

마지막으로 모든 기존 파일을 단일 형식으로 변환하고 새 파일이 해당 형식이어야하는 것이 더 낫지 않을까요?


5
이상한! 30 분 동안 중단 된 후이 주석을 처음 읽었을 때 "macroman"을 "macro man"으로 읽었으며 해당 문자열을 검색하여 OP가 언급했는지 여부를 확인할 때까지 MacRoman과 연결하지 않았습니다.
Adrian Pronk

+1이 답변은 흥미 롭습니다. 좋은 생각인지 나쁜 생각인지 확실하지 않습니다. 아무도 감지되지 않을 수있는 기존 인코딩을 생각할 수 있습니까? 미래에 하나가 될 가능성이 있습니까?
사용자 이름

1

무작위로 인코딩 된 수많은 레거시 텍스트 파일의 문제가있는 사람이 있습니까? 그렇다면 어떻게 해결하려고했으며 얼마나 성공적 이었습니까?

현재 파일을 XML로 변환하는 프로그램을 작성 중입니다. 텍스트 파일의 인코딩을 결정하는 문제의 상위 집합 인 각 파일의 유형을 자동으로 감지해야합니다. 인코딩을 결정하기 위해 베이지안 접근 방식을 사용하고 있습니다. 즉, 내 분류 코드는 텍스트 파일이 이해하는 모든 인코딩에 대해 특정 인코딩이있을 확률 (가능성)을 계산합니다. 그런 다음 프로그램은 가장 가능성이 높은 디코더를 선택합니다. 베이지안 접근 방식은 각 인코딩에 대해 이와 같이 작동합니다.

  1. 각 인코딩의 빈도에 따라 파일이 인코딩에 있을 초기 ( 이전 ) 확률을 설정합니다 .
  2. 파일의 각 바이트를 차례로 조사하십시오. 존재하는 해당 바이트 값과 실제로 해당 인코딩에있는 파일 간의 상관 관계를 확인하려면 바이트 값을 검색합니다. 이 상관 관계를 사용 하여 파일이 인코딩에 있을 새로운 ( 사후 ) 확률 을 계산합니다 . 검사 할 바이트가 더 많은 경우 다음 바이트를 검사 할 때 해당 바이트의 사후 확률을 사전 확률로 사용합니다.
  3. 파일의 끝에 도달하면 (실제로 처음 1024 바이트 만 살펴 봅니다) 파일이 인코딩에있을 가능성이 있습니다.

그것은 베이 즈가 '정리가되도록 증발하는 매우 대신 확률을 계산, 당신이 계산하면 쉽게 할 정보 내용 의 대수이며, 확률 : info = log(p / (1.0 - p)).

수동으로 분류 한 파일 모음을 검사하여 초기 사전 확률과 상관 관계를 계산해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.