【问题标题】:Remove ^@ character from a string从字符串中删除 ^@ 字符
【发布时间】:2015-01-25 17:42:00
【问题描述】:

我有以下问题。我有一个来自外部源的 CSV 文件,我正在尝试通过以下方式使用 Text::CSV 模块读取它

$csv = Text::CSV->new({binary => 1}) or die "Could not open $filename : ".Text::CSV->error_diag();

binmode("stdout", ":utf8");

open $fh, "<encoding(utf8)", $filename or die "Could not open $filename : $!\n";

while ($row = $csv->getline($fh)) {
    for ($i = 0; $i <= $#{$row}; $i++) {
        $data = encode("utf8", $row->[$i]);
        print "$data\n";
    }
    print "$row->[$keycol] => $row->[$valcol]\n";
    $hash{$row->[$keycol]} = $row->[$valcol];
}

$csv->eof() or die " Error--- $i ".($csv->error_diag())."\n";

但是,在从该文件中读取几行后,程序因错误而死。

经过检查,我发现数据中有一些列应该用引号括起来 " ... " 但只有一个引号。那里没有匹配的引号,而是这个奇怪的 ^@ 字符。如何用引号替换所有这些 ^@ 字符?这不是简单的 ASCII 所以我不能做$str =~ s/\^\@/\"/g

【问题讨论】:

  • 什么是$keycol?它没有在您显示的代码中定义。
  • 你必须总是 use strictuse warnings 在你编写的每个 Perl 程序的顶部,并尽可能使用 my 声明所有变量到他们的第一个使用点。
  • 你说,“程序因错误而死”。请问错误信息是什么?你用什么来查看^@ 字符?最有可能使用代码点为零来指示 NUL 字符。您的输入数据来自哪里?我认为如果数据确实包含不匹配的引号,您应该非常小心:很可能还有其他您没有注意到的问题。
  • Control-@也称为空字节'\0',用于终止字符串。这是根据@(64)的ASCII值,对比A(65)的ASCII值,而^A(control-A)就是'\1,所以^@就是'\0' .在将数据作为字符串处理时,这会给您带来潜在的问题——^@ 标记了字符串的结尾。
  • 感谢大家的指点。这确实看起来像一个数据问题,最好从数据的发送方解决,从接收方的角度来看似乎没有什么可做的。

标签: regex perl csv utf-8


【解决方案1】:

^@ 通常表示NUL(ASCII 00)。在 Perl 双引号和正则表达式中,可以用\c@\0\x00 等表示

$str =~ s/\c@/"/g;

当大多数人尝试删除 NUL 时,这是因为他们有未解码的 UTF-16。解决方案实际上是执行正确的解码和编码。目前尚不清楚这是否是您面临的问题。

【讨论】:

    【解决方案2】:

    我强烈建议您去找获得此文件的人,向他们索取一份他们没有在 MS Word 或其他任何文件中编辑过的副本。这听起来更像是您在描述一个文件,该文件已被一个相信更具装饰性的引号集形式的文字处理器所破坏,并且它正在用引号的“颠倒”版本替换其中一个。即“智能引号”。

    如果编辑器对双引号这样做,那么其中可能还有更多损坏的数据。从理论上讲,您也许可以使用 s/\x93/"/gs/\x94/"/g 来还原它们,但它们当然应该永远不会首先在 CSV 格式的文件中。

    【讨论】:

    • ...而这正是为什么被否决的?这两个正则表达式应该将任何时髦的“智能引号”转换回理智和合理的引号(即 \0x22,又名 ASCII 34),作为分类步骤。众所周知,做这种事情的编辑器也会弄乱省略号和减号(以及其他几个字符),并且对数据处理不友好。
    猜你喜欢
    • 2016-07-26
    • 2013-09-18
    • 2011-11-22
    • 2019-09-08
    相关资源
    最近更新 更多