Я нахожусь в процессе преобразования файлов, сгенерированных древней библиотечной программой для DOS кафедры китайских исследований нашего университета, во что-то более полезное и доступное.
Среди проблем, с которыми я сталкиваюсь, является то, чтоэкспортированные текстовые файлы (размером около 80 МБ) находятся в смешанной кодировке.Я на Windows.
Немецкие умляуты и другие символы с более высоким ASCII кодируются в cp1252, я думаю, и CJK-символы в GB18030.Из-за «перекрывающихся» кодировок я не могу просто перетащить весь файл в Word или что-то еще и позволить ему выполнить преобразование, потому что я получу что-то вроде этого:
orig:
+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 \x80-\xFF
.(Это версии ß, ú, ó, í
и "small nordic o with cross-stroke
" в кодировке cp1252, которые отображаются в строках в кодировке cp1252- и GB18030.)
прочитать весь файл и преобразовать егоот GB18030 до UTF8, таким образом преобразовывая закодированные китайские символы в настоящие китайские символы.
Преобразование буквенно-цифровых кодов обратно в их эквиваленты Unicode.
ХотяВ основном сценарий работает, возникает следующая проблема:
- После преобразования исходного файла размером 80 МБ Notepad ++ по-прежнему считает, что это файл ANSI, и отображает его как таковой.Мне нужно нажать «Кодирование-> Кодировать в UTF-8», чтобы правильно его отобразить.
Что я хотел бы знать, это:
Как правило, есть ли лучший подход для преобразования файла смешанного кодирования в UTF-8?
Если нет, следует ли мне использовать use utf8
, чтобы вместо него можно было напрямую вводить символыих шестнадцатеричного представления в подпрограмме codes2char
?
Решит ли спецификация в начале файла проблему NP ++, отображая ее изначально как файл ANSI?Если это так, как я должен изменить свой сценарий, чтобы выходной файл имел спецификацию?
После преобразования я могу захотеть вызвать еще несколько подпрограмм (например, чтобы преобразовать весь файл в формат 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;
вау, это было долго.Я надеюсь, что это не слишком запутанно
РЕДАКТИРОВАТЬ :
Это шестнадцатеричный пример приведенной выше строки:
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.)
и еще два для иллюстрации:
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).
В обоих случаях имеется шестнадцатеричное значение E1.В первом случае он стоит вместо немецкого sharp-s (ß, "Rußland" = "Russia"), а во втором случае он является частью многобайтового символа CJK reading (читается: "rou").
В библиотечной программе китайские символы вводятся и отображаются с помощью дополнительной программы, которая должна быть загружена первой и, насколько я могу судить, подключена к графическому драйверу на низком уровне, ловязакодированные китайские иероглифы и отображающие их как символы, оставляя все остальное в покоеУмлауты и т. Д. Обрабатываются самой библиотечной программой.
Я не до конца понимаю, как это работает, то есть как программы знают, следует ли рассматривать HexE1 как один символ á
и, таким образом, преобразовывать его в соответствии с codepage X
и когда он является частью многобайтового символа и, таким образом, преобразуется согласно codepage Y
Самое близкое приближение, которое я нашел, состоит в том, что специальные символы, вероятно, будут частью китайской строки, если есть другие специальные символы до или после нее. (например, ÎÂÈá¶Øºñ
)