source

MacRoman, CP1252, Latin1, UTF-8 및 ASC 사이의 부호화를 확실하게 추측하는 방법II

factcode 2022. 11. 5. 08:55
반응형

MacRoman, CP1252, Latin1, UTF-8 및 ASC 사이의 부호화를 확실하게 추측하는 방법II

직장에서 인코딩 관련 연결, 재해 또는 재해가 발생하지 않는 한 일주일은 없을 것 같습니다.이 문제는 보통 인코딩을 지정하지 않고도 "텍스트" 파일을 안정적으로 처리할 수 있다고 생각하는 프로그래머에서 발생합니다.하지만 당신은 그럴 수 없죠.

그래서 앞으로 파일 이름이 다음 문자로 끝나는 것을 금지하기로 결정되었습니다.*.txt ★★★★★★★★★★★★★★★★★」*.text이러한 확장으로 인해 캐주얼한 프로그래머가 인코딩에 대해 무미건조한 안일한 태도를 취하게 되어 부적절한 취급을 하게 되는 것으로 생각됩니다.적어도 자신이 무엇을 가지고 있는지 모른다는 을 알 수 있기 때문에, 연장이 전혀 없는 것이 거의 더 나을 것이다.

하지만 우리는 그렇게까지 할 생각이 없다.대신 인코딩으로 끝나는 파일 이름을 사용해야 합니다. 예를파일 에는 이런 요.README.ascii,README.latin1,README.utf8 등등.

특정 확장자를 필요로 하는 파일의 경우 Perl이나 Python 등의 파일 자체 내에서 인코딩을 지정할 수 있는 경우 이를 수행해야 합니다.하지 않는 합니다.SomeClass-utf8.java.

출력에는 UTF-8이 강하게 우선됩니다.

수천 을 어떻게 해야 하는지 .*.txt새로운 기준에 맞게 모든 이름을 바꾸고 싶습니다.하지만 우리가 그들 모두를 쳐다볼 수는 없어.그래서 우리는 실제로 작동하는 도서관이나 프로그램이 필요합니다.

이것들은 ASCII, ISO-8859-1, UTF-8, Microsoft CP1252, 또는 Apple MacRoman 의 어느쪽인가에 있습니다.ASCII인지 아닌지는 알 수 있지만 UTF-8인지 아닌지는 알 수 없지만 8비트 인코딩에 대해서는 고민하고 있습니다.Unix가 혼재된 환경(Solaris, Linux, Darwin)에서 실행 중이고 대부분의 데스크톱이 Mac으로 되어 있기 때문에 MacRoman 파일이 상당히 많습니다.그리고 이것들은 특히 문제다.

얼마 전부터 프로그래밍 방식으로 어느 것이 더 나은지 알아보는 방법을 찾고 있습니다.

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

파일이 입력되어 있는데, 3개의 다른 8비트 인코딩을 확실하게 구별할 수 있는 프로그램이나 라이브러리를 찾을 수 없습니다.MacRoman 파일만 해도 천 개가 넘어요 그러니 어떤 문자 집합 탐지기를 사용하든 그걸 탐지할 수 있을 거예요내가 본 어떤 것도 그 속임수를 다룰 수 없다.ICU charset detector 라이브러리에 큰 기대를 걸고 있었습니다만, MacRoman에는 대응할 수 없습니다.또한 Perl과 Python에서 동일한 작업을 수행하기 위한 모듈도 살펴보았지만 MacRoman을 탐지할 수 없습니다.

따라서 제가 찾고 있는 것은 파일이 있는 5개의 인코딩 중 어느 것이 더 바람직한지 확실하게 판별할 수 있는 기존 라이브러리 또는 프로그램입니다.특히 제가 인용한 3비트 부호화, 특히 MacRoman을 구별해야 합니다.파일은 99%가 넘는 영어 텍스트입니다.다른 언어로 된 것도 몇 개 있지만 많지는 않습니다.

라이브러리 코드일 경우 언어 설정은 Perl, C, Java 또는 Python 순으로 합니다.단순한 프로그램이라면 풀소스로 제공되고 Unix에서 실행되며 완전히 방해받지 않는 한 어떤 언어로 제공되든 상관없습니다.

수천 개의 레거시 텍스트 파일이 무작위로 인코딩되는 문제를 겪은 적이 있습니까?그렇다면, 어떻게 문제를 해결하려고 했고 얼마나 성공적이었습니까?이것이 제 질문의 가장 중요한 측면이지만, 프로그래머에게 파일의 실제 인코딩을 사용하여 파일 이름을 지정(또는 파일 이름을 변경)하도록 권장하는 것이 향후 문제를 회피하는 데 도움이 될 것이라고 생각하십니까?이를 제도적으로 시행하려고 한 적이 있는가? 만약 그렇다면, 성공적이었는가, 실패했는가? 그리고 그 이유는 무엇인가?

그리고 네, 저는 문제의 성격상 확답을 보장할 수 없는 이유를 충분히 이해합니다.특히 데이터가 부족하여 데이터를 유지할 수 없는 작은 파일의 경우에는 더욱 그렇습니다.다행히 파일 크기가 작을 때가 거의 없습니다. ★★★★★★★★★★★★★★★★★★★★★★★★★★README파일 대부분은 50k에서 250k 사이즈의 파일이며, 대부분은 더 큰 파일 크기가 더 큽니다.크기가 몇 K를 넘는 것은 모두 영어로 되어 있는 것이 보증합니다.

문제의 영역은 바이오메디컬 텍스트 마이닝입니다.따라서 PubMedCentral의 Open Access Respository와 같이 광범위하고 매우 큰 코퍼스를 다루기도 합니다.꽤 큰 파일은 바이오테소러스 6.0으로 5.7기가바이트입니다.이 파일은 거의 모든 UTF-8이기 때문에 특히 귀찮습니다.다만, 일부 numbskull은 Microsoft CP1252라고 하는 8비트 인코딩으로 되어 있는 몇 줄의 행이 그 안에 걸려 있었습니다.저걸 타려면 꽤 시간이 걸려요. :)

우선, 간단한 케이스:

ASCII

데이터에 0x7F 이상의 바이트가 포함되어 있지 않은 경우 ASCII가 됩니다.(또는 7비트 ISO646 인코딩이지만 매우 구식입니다.

UTF-8

데이터가 UTF-8로 검증되면 UTF-8로 간주할 수 있습니다.UTF-8의 엄격한 검증 규칙 때문에 잘못된 긍정은 극히 드물기 때문입니다.

ISO-8859-1과 Windows-1252 비교

이들 2개의 부호화의 유일한 차이점은 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(표준)는 양쪽 인코딩에서 동일합니다.ASC 이외의 것이 이것뿐일 경우2바이트, MacRoman을 선택하든 cp1252를 선택하든 상관없습니다.

통계적 접근법

UTF-8로 알고 있는 데이터의 문자(바이트가 아님!) 주파수를 카운트합니다.가장 빈번한 문자를 판별합니다.그런 다음 이 데이터를 사용하여 cp1252 또는 MacRoman 문자가 더 일반적인지 확인합니다.

제가 위키피디아 기사를 했을 때, 가장 인 비 ASC 문서인 의 영어 위키피디아 입니다.는 II 입니다.·•–é°®’èö—

  • 바이트 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 제안 바이트를 카운트하고 가장 큰 바이트를 선택합니다.

Mozilla nsUniversalDetector(Perl 바인딩:인코딩:검출/엔코드:검출:검출기)가 백만 배로 입증되었다.

그런 경험적 접근(ASCII와 UTF-8을 제외한다고 가정)을 시도합니다.

  • 0x7f~0x9f가 전혀 표시되지 않는 경우는 ISO-8859-1일 가능성이 있습니다.이는 컨트롤 코드가 거의 사용되지 않기 때문입니다.
  • 0x91 ~ 0x94 가 로트 표시되었을 경우는, Windows-1252 가 될 가능성이 있습니다.이는 "스마트 따옴표"가 영어 텍스트에서 사용될 가능성이 가장 높기 때문입니다.좀 더 확실하게 하기 위해 짝을 찾아보세요.
  • 그렇지 않으면 MacRoman입니다. 특히 0xd2에서 0xd5까지가 많은 경우(MacRoman에서 타이포그래픽 따옴표는 여기에 있습니다).

사이드 노트:

Java 소스 등 파일 내부에 이러한 기능이 존재하지 않는 파일의 경우 SomeClass-utf8.java와 같이 확장자 앞에 인코딩을 배치합니다.

이러지 마!!

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

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

"we stand a good change to know that something use imply 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에서 유래한 문자 집합 검출기는 MacRoman을 지원하지 않으며, AFAICT는 주어진 언어로 디코딩이 말이 되는지 확인하고, 구두점을 무시하고, 해당 언어의 다양한 문서를 기반으로 하기 때문에 어떤 경우에도 특히 영어에서는 잘 작동하지 않습니다.

다른 사용자가 언급했듯이 실제로 사용할 수 있는 것은 cp1252와 macroman을 구별하는 데 사용되는 높은 비트 집합 구두점 문자뿐입니다.셰익스피어나 핸사드나 KJV 성경이 아닌 모질라 타입의 모델을 교육하고 256바이트를 모두 고려하는 것이 좋습니다.당신의 파일에는 마크업(HTML, XML 등)이 포함되어 있지 않을 것으로 생각됩니다.이것은 뭔가 충격적인 일이 일어날 가능성을 왜곡하는 것입니다.

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

(1) ISO-8859-1로 부호화되어 있다고 생각되지만, 0x80~0x9F 범위의 「컨트롤 문자」를 포함한 파일.이는 HTML5 규격 초안에 cp1252를 사용하여 ISO-8859-1로 선언된 모든 HTML 스트림을 디코딩하도록 규정되어 있을 정도로 널리 퍼져 있습니다.

(2) UTF-8로 OK를 디코딩하지만, 결과적으로 Unicode에는 U+0080 ~ U+009F 범위의 "제어 문자"가 포함됩니다.이는 cp1252 / cp850 (seeen it accurred!) / etc 파일을 "ISO-8859-1"에서 UTF-8로 트랜스코딩하기 때문에 발생할 수 있습니다.

(웹이 아닌) 파일8비트 세트로 디텍터 wet-Sunday-afternoon 프로젝트.legacy ** n 및 cp850과 같은 것.아직 황금시간대에는 한참 멀었다.교육용 파일에 관심이 있습니다. ISO-8859-1/cp1252/MacRoman 파일도 다른 사람의 코드 솔루션과 마찬가지로 "장애가 없는" 파일입니까?

이미 알고 있듯이 이 문제를 해결하는 완벽한 방법은 없습니다.파일이 사용하는 인코딩에 대한 암묵적인 지식이 없으면 모든 8비트 인코딩이 완전히 동일하기 때문입니다.바이트 컬렉션모든 바이트는 모든 8비트 부호화에 유효합니다.

가장 바람직한 것은 바이트를 분석하는 알고리즘입니다.특정 바이트가 특정 언어에서 특정 인코딩과 함께 사용될 가능성에 기초하여 파일이 어떤 인코딩을 사용하는지 추측할 수 있습니다.그러나 이 경우 파일이 어떤 언어를 사용하는지 알아야 하며, 인코딩이 혼재된 파일이 있으면 전혀 쓸모가 없습니다.

파일내의 텍스트가 영어로 쓰여져 있는 것을 알고 있는 경우는, 그 파일에 사용하는 인코딩의 어느 쪽인가에 차이가 있는 것을 알 수 없습니다.이것은, 전술한 모든 인코딩의 차이가, 통상은 영어에서 사용되지 않는 문자를 지정하는 인코딩의 일부에 모두 현지화되어 있기 때문입니다.텍스트가 특수 형식 또는 구두점의 특수 버전(CP1252 등)을 사용하는 경우 문제가 발생할 수 있지만 텍스트의 요지에 대해서는 문제가 없을 수 있습니다.

macroman을 제외한 모든 부호화를 검출할 수 있다면 해독할 수 없는 부호화는 macroman으로 하는 것이 타당합니다.즉, 처리할 수 없는 파일 목록을 작성하여 마치 Macroman처럼 처리하십시오.

이러한 파일을 정렬하는 또 다른 방법은 사용자가 왜곡되지 않은 인코딩을 결정할 수 있는 서버 기반 프로그램을 만드는 것입니다.물론 사내에서도 가능하지만, 100명의 직원이 매일 몇 명씩 작업하기 때문에 순식간에 수천 개의 파일을 처리할 수 있습니다.

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

수천 개의 레거시 텍스트 파일이 무작위로 인코딩되는 문제를 겪은 적이 있습니까?그렇다면, 어떻게 문제를 해결하려고 했고 얼마나 성공적이었습니까?

저는 현재 파일을 XML로 변환하는 프로그램을 작성하고 있는데, 텍스트 파일의 인코딩을 결정하는 문제의 슈퍼셋인 각 파일의 형식을 자동 검출해야 합니다.인코딩을 결정하기 위해 베이지안 방식을 사용합니다.즉, 분류 코드는 텍스트 파일이 인식하는 모든 인코딩에 대해 특정 인코딩을 가질 확률(우도)을 계산합니다.그런 다음 가장 가능성이 높은 디코더를 선택합니다.베이지안 어프로치는, 각 부호화에 대해서 다음과 같이 동작합니다.

  1. 각 부호화의 빈도에 근거해, 파일이 부호화중의 초기() 확률을 설정합니다.
  2. 파일의 각 바이트를 차례로 조사합니다.바이트 값을 검색하여 존재하는 바이트 값과 해당 인코딩에 실제로 존재하는 파일 간의 상관 관계를 확인합니다.이 상관관계를 사용하여 파일이 인코딩되어 있을 새로운(후방) 확률을 계산합니다.검토할 바이트가 더 많은 경우 다음 바이트를 검사할 때 해당 바이트의 사후 확률을 이전 확률로 사용합니다.
  3. 파일의 마지막에 도달했을 때(실제로 처음 1024바이트만 참조), 파일이 인코딩되어 있을 가능성이 높아집니다.

Bayes의 정리는 확률 계산 대신 확률 로그인 정보 내용을 계산하면 매우 쉬워집니다.info = log(p / (1.0 - p)).

수동으로 분류한 파일의 말뭉치를 조사하여 초기 우선 확률과 상관관계를 계산해야 합니다.

승인된 답변 https://stackoverflow.com/a/4200765/2731103에 이끌려 요청된 인코딩을 대부분 올바르게 식별하기 위해 루비 보석 "model"을 개선할 수 있었습니다.

Import 전에 CSV 파일 인코딩을 검출하기 위한 실제 환경에서 사용합니다.

적절한 부분(루비)

UTF8HASBOM = /^\xEF\xBB\xBF/n      #  [239, 187, 191]
UTF32LEBOM = /^\xFF\xFE\x00\x00/n  # [255, 254, 0, 0]
UTF32BEBOM = /^\x00\x00\xFE\xFF/n  # [0, 0, 254, 255]

UTF16LEBOM = /^\xFF\xFE/n                # [255, 254]
UTF16BEBOM = /^\xFE\xFF/n                # [254, 255]

NOTIN1BYTE = /[\x00-\x06\x0B\x0E-\x1A\x1C-\x1F\x7F]/n
NOTISO8859 = /[\x00-\x06\x0B\x0E-\x1A\x1C-\x1F\x7F\x80-\x84\x86-\x9F]/n

# Information to identify MacRoman
# https://stackoverflow.com/questions/4198804/
NOTINCP1252 = /[\x81\x8D\x8F\x90\x9D]/n
CP1252CHARS = /[\x92\x95\x96\x97\xAE\xB0\xB7\xE8\xE9\xF6]/n
MCROMNCHARS = /[\x8E\x8F\x9A\xA1\xA5\xA8\xD0\xD1\xD5\xE1]/n
detect.force_encoding('BINARY') # Needed to prevent non-matching regex charset.
sample = detect[0..19]     # Keep sample string under 23 bytes.
detect.sub!(UTF8HASBOM, '') if sample[UTF8HASBOM] # Strip any UTF-8 BOM.

# See: http://www.daniellesucher.com/2013/07/23/ruby-case-versus-if/
if    sample.ascii_only? && detect.force_encoding('UTF-8').valid_encoding?

elsif sample[UTF32LEBOM] && detect.force_encoding('UTF-32LE').valid_encoding?
elsif sample[UTF32BEBOM] && detect.force_encoding('UTF-32BE').valid_encoding?
elsif sample[UTF16LEBOM] && detect.force_encoding('UTF-16LE').valid_encoding?
elsif sample[UTF16BEBOM] && detect.force_encoding('UTF-16BE').valid_encoding?

elsif detect.force_encoding('UTF-8').valid_encoding?

elsif detect.force_encoding('BINARY')[NOTISO8859].nil?
  detect.force_encoding('ISO-8859-1')

elsif detect.force_encoding('BINARY')[NOTIN1BYTE].nil?

  if  detect.force_encoding('BINARY')[NOTINCP1252].nil? &&
            detect.force_encoding('BINARY').scan(MCROMNCHARS).length < detect.force_encoding('BINARY').scan(CP1252CHARS).length

      detect.force_encoding('Windows-1252')
  else
      detect.force_encoding('MacRoman')
  end

else  detect.force_encoding('BINARY')
end

언급URL : https://stackoverflow.com/questions/4198804/how-to-reliably-guess-the-encoding-between-macroman-cp1252-latin1-utf-8-and

반응형