gpt4 book ai didi

perl - 关于在 Perl 中将混合编码文件转换为 UTF8 的问题

转载 作者:行者123 更新时间:2023-12-04 12:49:22 26 4
gpt4 key购买 nike

我正在将我们大学中文系基于 DOS 的古老图书馆程序生成的文件转换为更有用和更易于访问的文件。

我正在处理的问题之一是导出的文本文件(大小约为 80MB)采用混合编码。我在 Windows 上。

德语元音变音和其他更高的 ASCII 字符在 cp1252 中编码,我认为在 GB18030 中编码为 CJK 字符。由于“重叠”编码,我不能只是将整个文件拖到 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 范围内的另一个字符时才使用字母数字代码 \x80-\xFF . (这些是 ß, ú, ó, í 和“small nordic o with cross-stroke ”的 cp1252 编码版本,并且出现在 cp1252 和 GB18030 编码的字符串中。)
  • 读入整个文件并将其从GB18030转换为UTF8,从而将编码的汉字转换为真正的汉字。
  • 将字母数字代码转换回对应的 Unicode。

  • 虽然脚本大部分工作,但出现以下问题:
  • 转换原来的 80MB 文件后,Notepad++ 仍然认为它是一个 ANSI 文件并显示它。我需要按“编码-> UTF-8 编码”才能正确显示。

  • 我想知道的是:
  • 一般来说,是否有更好的方法将混合编码文件转换为 UTF-8?
  • 如果没有,我应该使用 use utf8这样我就可以在 codes2char 中直接输入字符而不是它们的十六进制表示子程序?
  • 文件开头的 BOM 会解决 NP++ 最初将其显示为 ANSI 文件的问题吗?如果是这样,我应该如何修改我的脚本以便输出文件有一个 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;

    哇,好长啊。我希望它不会太复杂

    编辑 :

    这是上面示例字符串的十六进制转储:
    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。在第一种情况下,它代表德语的尖锐 s (ß, "Rußland"="Russia"),在第二种情况下,它是多字节 CJK 字符柔的一部分(读作:“rou”)。

    在库程序中,汉字是通过一个额外的程序输入和显示的作为角色,而让其他一切都独自一人。德语变音等由库程序本身处理。

    我不完全理解这是如何工作的,即程序如何知道 HexE1 是否被视为单个字符 á并因此根据 codepage X 进行转换当它是多字节字符的一部分并因此根据 codepage Y 进行转换时

    我发现的最接近的近似值是,如果特殊字符前后有其他特殊字符,则它很可能是中文字符串的一部分。 (例如 ÎÂÈá¶Øºñ )

    最佳答案

  • 如果混合编码使得每行/记录/字段/任何内容都采用一致的编码,则您可以单独读取和转换每行/记录/字段/任何内容。但这听起来不像这里的情况。
  • 不会是一个坏主意。
  • UTF-8 通常不使用 BOM,但如果您真的想尝试输出字符 U+FEFF(在 UTF-8 中,这是 3 个字节 ef bb bf )。如果您能弄清楚为什么 NP++ 错误地检测到文件,那就更好了。
  • 在读取 UTF-8 编码的文件时,使用 UTF-8 输入层打开它是个好主意。如果您愿意,<:utf8是较短的等效于 < :encoding(UTF-8) .

  • 至于原始困惑是如何工作的,“附加程序”似乎只是将任何看起来像汉字的东西转换成中文,而将其他任何东西都保留下来(标准驱动程序然后使用欧洲编码显示),而“库程序”只是输出它收到的任何代码。因此,一种更直接的转换文件的方法可能是镜像:使用 :encoding(latin-1) 读入文件。 (或其他)然后替换中文字符(例如 s/\xc8\xe1/柔/ )。

    关于perl - 关于在 Perl 中将混合编码文件转换为 UTF8 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6897982/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com