現在、私たちの大学の中国研究科の古い 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 文字を変換するいくつかのサブルーチンを含むスクリプトを作成しました。次のことを行います(特に):
一部の上位 ASCII 文字 (š、á など) を英数字コードに置き換えます (ファイルの他の場所に自然に現れる可能性は低いです)。例:
-Min, Jie / (šbers.)
->-Min, Jie / (uumlautgrossbers.)
注: 「変換表」を手動で作成したため、ドキュメントに実際に表示される特殊文字のみを考慮しました。したがって、変換は完全には完了していませんが、私の場合、適切な結果が得られます。私たちの本はほとんどがドイツ語、英語、中国語で書かれており、イタリア語、スペイン語、フランス語などの言語はごくわずかで、チェコ語などはほとんどないからです。上位 ASCII 範囲の別の文字が先行または後続していない場合にのみ
á, £, ¢, ¡, í
、英数字コードに置き換えます。(これらはおよび " " の cp1252 エンコード バージョンであり、cp1252 および GB18030 エンコード文字列の両方に表示されます。)\x80-\xFF
ß, ú, ó, í
small nordic o with cross-stroke
ファイル全体を読み取り、GB18030 から UTF8 に変換します。これにより、エンコードされた中国語の文字が実際の中国語の文字に変換されます。
英数字コードを Unicode に変換して戻します。
スクリプトはほとんど機能しますが、次の問題が発生します。
- 元の 80MB ファイルを変換した後も、Notepad++ はそれが ANSI ファイルであると認識し、そのように表示します。正しく表示するには、「エンコード-> UTF-8でエンコード」を押す必要があります。
私が知りたいのは:
一般に、混合エンコーディング ファイルを UTF-8 に変換するためのより良い方法はありますか?
そうでない場合は、サブルーチン
use utf8
で 16 進数表現の代わりに文字を直接入力できるように使用する必要がありますか?codes2char
ファイルの先頭にある BOM は、最初に ANSI ファイルとして表示される NP++ の問題を解決しますか? その場合、出力ファイルに BOM が含まれるようにスクリプトをどのように変更すればよいですか?
変換後、さらにいくつかのサブルーチンを呼び出したい場合があります (たとえば、ファイル全体を 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 X
codepage Y
私が見つけた最も近い概算は、その前後に他の特殊文字がある場合、特殊文字は中国語の文字列の一部である可能性が高いということです。(例ÎÂÈá¶Øºñ
)