문제

우리 애플리케이션에서는 텍스트 파일(.txt, .csv, 등) 다양한 소스에서.파일을 읽을 때 파일이 다른/알 수 없는 코드 페이지에서 생성되었기 때문에 때때로 가비지가 포함되어 있습니다.

텍스트 파일의 코드 페이지를 (자동으로) 감지하는 방법이 있습니까?

그만큼 detectEncodingFromByteOrderMarks, 에 StreamReader 생성자, 작업 UTF8 및 기타 유니코드로 표시된 파일이 있지만 다음과 같은 코드 페이지를 감지하는 방법을 찾고 있습니다. ibm850, windows1252.


귀하의 답변에 감사드립니다. 이것이 제가 한 일입니다.

우리가 받은 파일은 최종 사용자로부터 온 것이며, 그들은 코드 페이지에 대한 단서가 없습니다.수신자도 최종 사용자이므로 코드 페이지에 대해 알고 있는 내용은 다음과 같습니다.코드 페이지가 존재하며 성가시다.

해결책:

  • 메모장에서 받은 파일을 열고 깨진 텍스트를 살펴보세요.누군가가 프랑수아 같은 이름을 가지고 있다면 인간의 지능으로 이것을 짐작할 수 있습니다.
  • 사용자가 파일을 여는 데 사용할 수 있는 작은 앱을 만들고, 올바른 코드 페이지가 사용될 때 파일에 표시될 텍스트를 사용자가 입력할 수 있도록 했습니다.
  • 모든 코드 페이지를 반복하고 사용자가 제공한 텍스트와 함께 솔루션을 제공하는 코드 페이지를 표시합니다.
  • 하나 이상의 코드 페이지가 나타나면 사용자에게 추가 텍스트를 지정하도록 요청하십시오.
도움이 되었습니까?

해결책

코드페이지를 감지할 수 없으므로 이를 알려주어야 합니다.바이트를 분석하고 추측할 수 있지만 이로 인해 이상한(때로는 재미있는) 결과가 나올 수 있습니다.지금은 찾을 수 없지만 메모장을 속여서 영어 텍스트를 중국어로 표시할 수 있다고 확신합니다.

어쨌든, 읽어야 할 내용은 다음과 같습니다.모든 소프트웨어 개발자가 유니코드 및 문자 집합에 대해 절대적으로, 적극적으로 알아야 하는 최소한의 정보(변명의 여지가 없습니다!).

특히 조엘은 이렇게 말합니다.

인코딩에 관한 가장 중요한 사실

방금 설명드린 내용을 모두 잊어버리셨다면, 아주 중요한 사실 한 가지만 기억해 주시기 바랍니다.어떤 인코딩을 사용하는지 알지 못한 채 문자열을 갖는 것은 의미가 없습니다.더 이상 모래 속에 머리를 집어넣고 "일반" 텍스트가 ASCII인 척할 수 없습니다.일반 텍스트 같은 것은 없습니다.

메모리, 파일 또는 전자 메일 메시지에 문자열이 있는 경우 해당 문자열이 어떤 인코딩으로 되어 있는지 알아야 합니다. 그렇지 않으면 문자열을 해석하거나 사용자에게 올바르게 표시할 수 없습니다.

다른 팁

UTF가 아닌 인코딩(예:BOM 없음) 기본적으로 텍스트에 대한 경험적 방법과 통계적 분석이 필요합니다.당신은 다음을 살펴보고 싶을 수도 있습니다 범용 문자 집합 감지에 관한 Mozilla 문서 (Wayback Machine을 통해 더 나은 형식을 갖춘 동일한 링크).

시도해 보셨나요? Mozilla Universal Charset Detector용 C# 포트

http://code.google.com/p/ude/

public static void Main(String[] args)
{
    string filename = args[0];
    using (FileStream fs = File.OpenRead(filename)) {
        Ude.CharsetDetector cdet = new Ude.CharsetDetector();
        cdet.Feed(fs);
        cdet.DataEnd();
        if (cdet.Charset != null) {
            Console.WriteLine("Charset: {0}, confidence: {1}", 
                 cdet.Charset, cdet.Confidence);
        } else {
            Console.WriteLine("Detection failed.");
        }
    }
}    

코드페이지를 감지할 수 없습니다.

이것은 분명히 거짓입니다.모든 웹 브라우저에는 인코딩이 전혀 표시되지 않은 페이지를 처리하기 위한 일종의 범용 문자 집합 감지기가 있습니다.Firefox에는 하나가 있습니다.코드를 다운로드하고 어떻게 작동하는지 확인할 수 있습니다.일부 문서 보기 여기.기본적으로 이는 경험적 방법이지만 매우 잘 작동합니다.

적당한 양의 텍스트가 주어지면 언어를 감지하는 것도 가능합니다.

여기 또 하나 있어요 방금 Google을 사용하여 찾았습니다.

이 질문에 대해서는 너무 늦었다는 것을 알고 있으며 이 솔루션은 영어 중심의 편견과 통계/실증적 테스트가 부족하기 때문에 일부 사람들에게는 매력적이지 않을 것입니다. 그러나 특히 업로드된 CSV 데이터를 처리하는 데는 매우 효과적이었습니다.

http://www.architectshack.com/TextFileEncodingDetector.ashx

장점:

  • BOM 감지 내장
  • 기본/대체 인코딩 사용자 정의 가능
  • (내 경험상) UTF-8과 Latin-1 스타일 파일이 혼합된 이국적인 데이터(예: 프랑스어 이름)가 포함된 서유럽 기반 파일(기본적으로 미국과 서유럽 환경의 대부분)에 대해 매우 안정적입니다.

메모:저는 이 수업을 쓴 사람이므로 당연히 무시하세요!:)

메모장++ 이 기능은 기본적으로 제공됩니다.변경하는 것도 지원합니다.

다른 해결책을 찾다가 발견했습니다.

https://code.google.com/p/ude/

이 솔루션은 좀 무겁습니다.

4개의 첫 번째 바이트와 아마도 XML 문자 집합 감지를 기반으로 하는 몇 가지 기본 인코딩 감지가 필요했습니다. 그래서 인터넷에서 일부 샘플 소스 코드를 가져와 약간 수정된 버전을 추가했습니다.

http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

Java용으로 작성되었습니다.

    public static Encoding DetectEncoding(byte[] fileContent)
    {
        if (fileContent == null)
            throw new ArgumentNullException();

        if (fileContent.Length < 2)
            return Encoding.ASCII;      // Default fallback

        if (fileContent[0] == 0xff
            && fileContent[1] == 0xfe
            && (fileContent.Length < 4
                || fileContent[2] != 0
                || fileContent[3] != 0
                )
            )
            return Encoding.Unicode;

        if (fileContent[0] == 0xfe
            && fileContent[1] == 0xff
            )
            return Encoding.BigEndianUnicode;

        if (fileContent.Length < 3)
            return null;

        if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf)
            return Encoding.UTF8;

        if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76)
            return Encoding.UTF7;

        if (fileContent.Length < 4)
            return null;

        if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0)
            return Encoding.UTF32;

        if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff)
            return Encoding.GetEncoding(12001);

        String probe;
        int len = fileContent.Length;

        if( fileContent.Length >= 128 ) len = 128;
        probe = Encoding.ASCII.GetString(fileContent, 0, len);

        MatchCollection mc = Regex.Matches(probe, "^<\\?xml[^<>]*encoding[ \\t\\n\\r]?=[\\t\\n\\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline);
        // Add '[0].Groups[1].Value' to the end to test regex

        if( mc.Count == 1 && mc[0].Groups.Count >= 2 )
        {
            // Typically picks up 'UTF-8' string
            Encoding enc = null;

            try {
                enc = Encoding.GetEncoding( mc[0].Groups[1].Value );
            }catch (Exception ) { }

            if( enc != null )
                return enc;
        }

        return Encoding.ASCII;      // Default fallback
    }

파일에서 처음 1024바이트를 읽는 것만으로도 충분하지만 전체 파일을 로드하고 있습니다.

누군가가 93.9%의 해결책을 찾고 있다면.이것은 나에게 효과적입니다.

public static class StreamExtension
{
    /// <summary>
    /// Convert the content to a string.
    /// </summary>
    /// <param name="stream">The stream.</param>
    /// <returns></returns>
    public static string ReadAsString(this Stream stream)
    {
        var startPosition = stream.Position;
        try
        {
            // 1. Check for a BOM
            // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/
            var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
            return streamReader.ReadToEnd();
        }
        catch (DecoderFallbackException ex)
        {
            stream.Position = startPosition;

            // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1.
            var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252));
            return streamReader.ReadToEnd();
        }
    }
}

저는 Python에서 비슷한 작업을 수행했습니다.기본적으로 다양한 인코딩의 많은 샘플 데이터가 필요합니다. 이 데이터는 슬라이딩 2바이트 창으로 분류되어 인코딩 목록 값을 제공하는 바이트 쌍으로 입력된 사전(해시)에 저장됩니다.

해당 사전(해시)이 주어지면 입력 텍스트를 가져와서 다음을 수행합니다.

  • BOM 문자(UTF-16-BE의 경우 '\xfe\xff', UTF-16-LE의 경우 '\xff\xfe', UTF-8의 경우 '\xef\xbb\xbf' 등)로 시작하는 경우 I 제안대로 처리
  • 그렇지 않다면 충분히 큰 텍스트 샘플을 취하고 샘플의 모든 바이트 쌍을 취한 다음 사전에서 제안된 가장 일반적이지 않은 인코딩을 선택합니다.

UTF로 인코딩된 텍스트도 샘플링한 경우 ~ 아니다 임의의 BOM으로 시작하면 두 번째 단계에서는 첫 번째 단계에서 누락된 항목을 처리합니다.

지금까지는 오류율이 줄어들면서 저에게 효과적이었습니다(샘플 데이터와 후속 입력 데이터는 다양한 언어로 된 자막임).

StreamReader 클래스의 생성자는 '인코딩 감지' 매개변수를 사용합니다.

"uchardet" 도구는 각 문자 세트에 대한 문자 빈도 분포 모델을 사용하여 이를 잘 수행합니다.더 큰 파일과 더 많은 "일반적인" 파일은 더 많은 신뢰도를 갖습니다(분명히).

우분투에서는 그냥 apt-get install uchardet.

다른 시스템에서는 여기에서 소스, 사용법 및 문서를 얻으세요. https://github.com/BYVoid/uchardet

C 라이브러리에 연결할 수 있으면 다음을 사용할 수 있습니다. libenca.보다 http://cihar.com/software/enca/.매뉴얼 페이지에서:

ENCA는 주어진 텍스트 파일 또는 아무도없는 경우 표준 입력을 읽고, 언어에 대한 지식 (귀하가 지원해야 함)과 구문 분석, 통계 분석, 추측 및 흑 마법의 혼합을 사용하여 인코딩을 결정합니다.

GPL v2입니다.

동일한 문제가 발생했지만 아직 자동으로 감지하는 좋은 해결책을 찾지 못했습니다.지금은 PsPad(www.pspad.com)를 사용하고 있습니다. ;) 잘 작동합니다

이는 기본적으로 경험적 방법으로 귀결되므로 동일한 소스에서 이전에 받은 파일의 인코딩을 첫 번째 힌트로 사용하는 것이 도움이 될 수 있습니다.

대부분의 사람들(또는 응용 프로그램)은 동일한 컴퓨터에서 매번 거의 동일한 순서로 작업을 수행하므로 Bob이 .csv 파일을 만들어 Mary에게 보낼 때 항상 Windows-1252 또는 그의 기계가 기본적으로 설정하는 것이 무엇이든.

가능한 경우 약간의 고객 교육도 나쁘지 않습니다. :-)

실제로 파일 인코딩을 감지하는 프로그래밍 방식이 아닌 일반적인 방법을 찾고 있었지만 아직 찾지 못했습니다.다른 인코딩으로 테스트하여 찾은 것은 내 텍스트가 UTF-7이라는 것입니다.

그래서 제가 처음으로 했던 곳은 다음과 같습니다.StreamReader 파일 = File.OpenText(fullfilename);

나는 그것을 다음과 같이 바꿔야했습니다 :StreamReader 파일 = new StreamReader(fullfilename, System.Text.Encoding.UTF7);

OpenText는 UTF-8이라고 가정합니다.

또한이 새로운 streamreader (fullFilename, true)와 같은 streamreader를 만들 수 있습니다. 두 번째 매개 변수는 파일의 바이트 오더 마크에서 인코딩을 시도하고 감지해야하지만 제 경우에는 작동하지 않았습니다.

AkelPad에서 파일을 열고(또는 잘못된 텍스트를 복사/붙여넣기) 편집 -> 선택 -> 코딩...으로 이동합니다.-> "자동 감지"를 확인하십시오.

ITmeze 게시물의 애드온으로 이 기능을 사용하여 Mozilla Universal Charset Detector용 C# 포트의 출력을 변환했습니다.

    private Encoding GetEncodingFromString(string codePageName)
    {
        try
        {
            return Encoding.GetEncoding(codePageName);
        }
        catch
        {
            return Encoding.ASCII;
        }
    }

MSDN

감사해요 @에릭 아론스티 언급을 위해 uchardet.

한편 Linux에는 (동일한?) 도구가 존재합니다. chardet.
또는 cygwin에서는 다음을 사용할 수도 있습니다. chardetect.

보다: chardet 매뉴얼 페이지: https://www.commandlinux.com/man-page/man1/charDetect.1.html

이는 주어진 각 파일의 문자 인코딩을 경험적으로 감지(추측)하고 각 파일에서 감지된 문자 인코딩에 대한 이름과 신뢰 수준을 보고합니다.

이 질문을 받은 지 10년(!)이 지났지만 여전히 GPL이 아닌 MS의 좋은 솔루션에 대한 언급이 없습니다. IMultiLanguage2 API.

이미 언급된 대부분의 라이브러리는 Mozilla의 UDE를 기반으로 하며 브라우저가 이미 유사한 문제를 해결한 것이 타당해 보입니다.나는 크롬의 솔루션이 무엇인지 모르지만 IE 5.0 MS가 출시한 이후로 다음과 같습니다.

  1. GPL 및 유사한 라이센스 문제가 없습니다.
  2. 아마도 영원히 지원되고 유지될 것입니다.
  3. 풍부한 출력 제공 - 신뢰도 점수와 함께 인코딩/코드 페이지에 대한 모든 유효한 후보,
  4. 놀랍게도 사용하기 쉽습니다(단일 함수 호출입니다).

기본 COM 호출이지만 여기 아주 좋은 작품이 있어요 .net 사용에 대한 상호 운용성 혼란을 처리하는 Carsten Zeumer가 작성했습니다.주변에 다른 도서관도 있지만 전반적으로 이 도서관은 마땅한 관심을 받지 못합니다.

나는 이 코드를 사용하여 파일을 읽을 때 유니코드와 Windows 기본 ANSI 코드 페이지를 감지합니다.다른 코딩의 경우 수동으로 또는 프로그래밍을 통해 내용을 확인해야 합니다.텍스트를 열었을 때와 동일한 인코딩으로 텍스트를 저장하는 데 사용할 수 있습니다.(저는 VB.NET을 사용합니다)

'Works for Default and unicode (auto detect)
Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) 
MyEditTextBox.Text = mystreamreader.ReadToEnd()
Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding
mystreamreader.Close()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top