【问题标题】:Perl unicode file with non-unicode content具有非 unicode 内容的 Perl unicode 文件
【发布时间】:2012-07-06 12:19:40
【问题描述】:

软件正在生成 UTF-8 文件,但将内容写入非 unicode 文件。我无法更改该软件,必须按现在的样子获取输出。不知道这是否会正确显示在此处,但德语变音符号“ä”在文件中显示为“ä”。

如果我在 Notepad++ 中打开文件,它会告诉我该文件是 UTF-8(无 BOM)编码的。现在,如果我在记事本中说“转换为 ANSI”,然后将文件编码切换回 UTF-8(不转换),则文件中的德语变音符号是正确的。如何在 Perl 中实现完全相同的行为?无论我到现在为止尝试过什么,变音符号都变得更糟了。

要重现,请为自己创建一个 UTF-8 编码文件并向其中写入内容:

好的,我试试。自己创建一个 UTF-8 文件并将其写入: Männer Schüle Vöogel SüÃ

然后,在 UTF-8 mysql 数据库上,创建一个表,其中 varchar 字段采用 UTF8_unicode 编码。现在,使用这个脚本:

use utf8;
use DBI;
use Encode;
if (open FILE, "test.csv") {
  my $db = DBI->connect(
    'DBI:mysql:your_db;host=127.0.0.1;mysql_compression=1', 'root', 'Yourpass',
    { PrintError => 1 }
  );
  my $sql="";
  my $sql = qq{SET NAMES 'utf8';};
  $db->do($sql);
  while (my $line = <FILE>) {
    my $sth = $db->prepare("INSERT IGNORE INTO testtable (testline) VALUES (?);");
    $sth->execute($line);
  }
}

文件的确切内容将被写入数据库。但是,我期望在数据库中的输出是德语变音符号:

Männer Schüler Vögel Süß

那么,我怎样才能正确转换呢?

【问题讨论】:

  • 没有“非 unicode 文件”之类的东西。请提供您的输入示例、有效的脚本、当前输出和预期输出,以便人们知道您的问题出在哪里。
  • 我用一些代码和示例数据扩展了我的文本。
  • 离题:您应该将prepare 放在while 循环之外。按照您的方式,prepare 很昂贵,并且将为您文件的每一行完成。请参阅the DBI doc outline section 了解更多信息。
  • 尝试添加$line = utf8::decode($line); 行作为while 循环的第一条语句。
  • 关于准备的好建议,谢谢:)

标签: perl file unicode utf-8


【解决方案1】:

具有讽刺意味的是:在我看来,您所说的软件并不是在编写“非 unicode 内容”(这毫无意义)——它会将其编码为 UTF-8 两次。让我们以这个ä 字符为例:它在UTF-8 中用两个字节表示,%C3 %A4。但随后该程序中的某些内容决定将这些字节视为 Latin-1 编码:因此它们成为两个单独的字符(最终将被编码为 UTF-8,这就是将保存到文件中的内容)。

我想扭转这种情况的最简单方法是让 Perl 在处理从文件中读取的字符串时认为它使用一系列字节(而不是字符序列)。它可以做得很简单(也很丑陋)......

open my $fh, '<:utf8', $file_name or die $!;
my $string = <$fh>;              # a sequence of characters            
$string = utf8::decode($string); # ... will be considered a sequence of octets

【讨论】:

    【解决方案2】:

    听起来像是第二次转换它,假设它是 ISO 8859-15 之类的东西,然后将其转换为 UTF-8。您可以通过将 UTF-8 转换为 ISO 8859-15(或任何似乎对您的数据有意义的编码)来扭转这种情况。

    正如http://www.fileformat.info/info/unicode/char/E4/index.htm 所见,字节 0xC3 0xA4 是ä 的有效 UTF-8 编码。当被视为 ISO 8859-15(或 8859-1、Windows-1252 或许多其他 8 位编码)时,它们会显示字符串 ä

    【讨论】:

    • 这很讽刺。我尝试了很多东西,但总是开始认为“它是 utf-8,所以我必须从 utf-8 转换为其他编码”。但它是如此简单,也许对我来说很简单......这是我现在使用的,只是从 utf8 转换为 latin1,效果很好:$line=encode("latin1", decode("utf8" , $line));
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多