7

現在、私たちの大学の中国研究科の古い DOS ベースのライブラリ プログラムによって生成されたファイルを、より便利でアクセスしやすいものに変換しています。

私が対処している問題の 1 つは、エクスポートされたテキスト ファイル (サイズが約 80MB) が混合エンコーディングになっていることです。私はWindowsを使用しています。

ドイツ語のウムラウトやその他の上位 ASCII 文字は cp1252 でエンコードされていると思いますが、CJK 文字は GB18030 でエンコードされていると思います。エンコーディングが「重複」しているため、ファイル全体を Word などにドラッグして変換させることはできません。次のような結果が得られるためです。

元:

+Autor:
-Yan, Lianke / ÑÖÁ¬¿Æ      # encoded Chinese characters
+Co-Autor:
-Min, Jie / (šbers.)       # encoded German U-umlaut (Ü)

結果:

+Autor:
-Yan, Lianke / 阎连科       # good
+Co-Autor:
-Min, Jie / (歜ers.)       # bad... (should be: "Übers.")

そこで、いくつかのステップで非 ASCII 文字を変換するいくつかのサブルーチンを含むスクリプトを作成しました。次のことを行います(特に):

  1. 一部の上位 ASCII 文字 (š、á など) を英数字コードに置き換えます (ファイルの他の場所に自然に現れる可能性は低いです)。例: -Min, Jie / (šbers.)->-Min, Jie / (uumlautgrossbers.)
    注: 「変換表」を手動で作成したため、ドキュメントに実際に表示される特殊文字のみを考慮しました。したがって、変換は完全には完了していませんが、私の場合、適切な結果が得られます。私たちの本はほとんどがドイツ語、英語、中国語で書かれており、イタリア語、スペイン語、フランス語などの言語はごくわずかで、チェコ語などはほとんどないからです。

  2. 上位 ASCII 範囲の別の文字が先行または後続していない場合にのみá, £, ¢, ¡, í、英数字コードに置き換えます。(これらはおよび " " の cp1252 エンコード バージョンであり、cp1252 および GB18030 エンコード文字列の両方に表示されます。)\x80-\xFFß, ú, ó, ísmall nordic o with cross-stroke

  3. ファイル全体を読み取り、GB18030 から UTF8 に変換します。これにより、エンコードされた中国語の文字が実際の中国語の文字に変換されます。

  4. 英数字コードを Unicode に変換して戻します。

スクリプトはほとんど機能しますが、次の問題が発生します。

  • 元の 80MB ファイルを変換した後も、Notepad++ はそれが ANSI ファイルであると認識し、そのように表示します。正しく表示するには、「エンコード-> UTF-8でエンコード」を押す必要があります。

私が知りたいのは:

  1. 一般に、混合エンコーディング ファイルを UTF-8 に変換するためのより良い方法はありますか?

  2. そうでない場合は、サブルーチンuse utf8で 16 進数表現の代わりに文字を直接入力できるように使用する必要がありますか?codes2char

  3. ファイルの先頭にある BOM は、最初に ANSI ファイルとして表示される NP++ の問題を解決しますか? その場合、出力ファイルに BOM が含まれるようにスクリプトをどのように変更すればよいですか?

  4. 変換後、さらにいくつかのサブルーチンを呼び出したい場合があります (たとえば、ファイル全体を CSV または ODS 形式に変換するため)。codes2charサブルーチンの開始ステートメントを引き続き使用する必要がありますか?

コードは、最後に呼び出されるいくつかのサブルーチンで構成されています。

!perl -w
use strict; 
use warnings;
use Encode qw(decode encode); 
use Encode::HanExtra;

our $input = "export.txt";
our $output = "export2.txt";

sub switch_var {                # switch Input and Output file between steps
    ($input, $output) = ($output, $input);
}

sub specialchars2codes {
open our $in, "<$input" or die "$!\n"; 
open our $out, ">$output" or die "$!\n"; 

while( <$in> )  {   
    ## replace higher ASCII characters such as a-umlaut etc. with codes.
    s#\x94#oumlautklein#g;
    s#\x84#aumlautklein#g;
    s#\x81#uumlautklein#g;
    ## ... and some more. (ö, Ö, ä, Ä, Ü, ü, ê, è, é, É, â, á, à, ì, î, 
    ## û, ù, ô, ò, ç, ï, a°, e-umlaut and ñ in total.)

    ## replace problematic special characters (ß, ú, ó, í, ø, ') with codes.
    s#(?<![\x80-\xFF])\xE1(?![\x80-\xFF])#eszett#g;
    s#(?<![\x80-\xFF])\xA3(?![\x80-\xFF])#uaccentaiguklein#g;
    s#(?<![\x80-\xFF])\xA2(?![\x80-\xFF])#oaccentaiguklein#g;
    s#(?<![\x80-\xFF])\xA1(?![\x80-\xFF])#iaccentaiguklein#g;
    s#(?<![\x80-\xFF])\xED(?![\x80-\xFF])#nordischesoklein#g;

    print $out $_;
    }   
close $out;
close $in;
}

sub convert2unicode {

open(our $in,  "< :encoding(GB18030)", $input)  or die "$!\n";
open(our $out, "> :encoding(UTF-8)",  $output)  or die "$!\n";

print "Convert ASCII to UTF-8\n\n";

while (<$in>) {         
        print $out $_;      
}

close $in;
close $out;
}

sub codes2char {

open(our $in,  "< :encoding(UTF-8)", $input)    or die "$!\n";
open(our $out, "> :encoding(UTF-8)", $output)   or die "$!\n";

print "replace Codes with original characters.\n";


    while (<$in>) {
        s#lidosoumlautklein#\xF6#g;
        s#lidosaumlautklein#\xE4#g;
        s#lidosuumlautklein#\xFC#g;
        ## ... and some more.
        s#eszett#\xDF#g;
        s#uaccentaiguklein#\xFA#g;
        s#oaccentaiguklein#\xF3#g;
        s#iaccentaiguklein#\xED#g;
        s#nordischesoklein#\xF8#g;

        print  $out $_;
    }
close($in)   or die "can't close $input: $!";
close($out)  or die "can't close $output: $!";
}

##################
## Main program ##
##################

&specialchars2codes;
&switch_var;
&convert2unicode;
&switch_var;
&codes2char;

うわー、これは長かった。あまり複雑でないことを願っています

編集

これは、上記の例の文字列の 16 進ダンプです。

01A36596                                                        2B 41                    +A
01A365A9   75 74 6F 72 3A 0D 0A 2D  59 61 6E 2C 20 4C 69 61  6E 6B 65   utor:  -Yan, Lianke
01A365BC   20 2F 20 D1 D6 C1 AC BF  C6 0D 0A 2B 43 6F 2D 41  75 74 6F    / ÑÖÁ¬¿Æ  +Co-Auto
01A365CF   72 3A 0D 0A 2D 4D 69 6E  2C 20 4A 69 65 20 2F 20  28 9A 62   r:  -Min, Jie / (šb
01A365E2   65 72 73 2E 29 0D 0A                                         ers.)  

説明する別の 2 つ:

1.

000036B3                                                     2D 52 75                   -Ru
000036C6   E1 6C 61 6E 64 0D 0A                                         áland  

2.

015FE030            2B 54 69 74 65  6C 3A 0D 0A 2D 57 65 6E  72 6F 75      +Titel:  -Wenrou
015FE043   64 75 6E 68 6F 75 20 20  CE C2 C8 E1 B6 D8 BA F1  20 28 47   dunhou  ÎÂÈá¶Øºñ (G
015FE056   65 6E 74 6C 65 6E 65 73  73 20 61 6E 64 20 4B 69  6E 64 6E   entleness and Kindn
015FE069   65 73 73 29 2E 0D 0A                                         ess).  

どちらの場合も、16 進値 E1 があります。最初の例では、ドイツ語のシャープ s (ß、"Rußland"="Russia") を表し、2 番目の例では、マルチバイトの CJK 文字柔 (読み方: "rou") の一部です。

ライブラリプログラムでは、最初にロードする必要がある追加のプログラムで中国語の文字が入力および表示され、私が知る限り、低レベルでグラフィックスドライバーにフックされ、エンコードされた中国語の文字をキャッチして表示します他のすべてを放っておく間、キャラクターとして。ドイツ語のウムラウトなどは、ライブラリ プログラム自体によって処理されます。

これがどのように機能するか、つまり、HexE1 が単一の文字として扱われ、マルチバイト文字の一部であり、áしたがって変換される場合に応じて変換されるかどうかをプログラムがどのように認識するかを完全には理解していません。codepage Xcodepage Y

私が見つけた最も近い概算は、その前後に他の特殊文字がある場合、特殊文字は中国語の文字列の一部である可能性が高いということです。(例ÎÂÈá¶Øºñ)

4

1 に答える 1

2
  1. 混合エンコーディングが、各行/レコード/フィールド/何でも一貫したエンコーディングであるようなものである場合、各行/レコード/フィールド/何でも個別に読み取って変換することができます。しかし、それはここの場合のようには聞こえません。
  2. 悪い考えではないでしょう。
  3. UTF-8は通常BOMを使用しませんが、実際に試してみたい場合は、文字U + FEFF(UTF-8では3バイトef bb bf)を出力します。NP++がファイルを誤検出している理由を正確に把握できればより良いでしょう。
  4. UTF-8でエンコードされたファイルを読み取るときは、UTF-8入力レイヤーで開くことをお勧めします。必要に応じて、<:utf8はに相当する短いもの< :encoding(UTF-8)です。

元の混乱がどのように機能するかについては、「追加プログラム」は漢字のように見えるものをすべて中国語に変換し、他のものはそのままにしておくようです(標準のドライバーはヨーロッパのエンコーディングを使用して表示します)。ライブラリプログラム」は、受信したコードを出力するだけです。したがって、ファイルを変換するより簡単な方法は、これをミラーリングすることです。:encoding(latin-1)(または何でも)を使用してファイルを読み込み、漢字を置き換えます(例s/\xc8\xe1/柔/)。

于 2011-08-01T15:36:17.327 に答える