【问题标题】:String corruption and nonprintable characters using XML::Twig in Win32 Perl在 Win32 Perl 中使用 XML::Twig 的字符串损坏和不可打印字符
【发布时间】:2010-12-14 19:40:39
【问题描述】:

这是一个非常奇怪的问题。我几乎花了一整天的时间将它缩减为一个可以充分展示问题的小型可执行脚本。

问题摘要:我正在使用XML::Twig 从 XML 文件中提取数据 sn-p,然后我将该数据 sn-p 粘贴到另一条数据的中间,我们称之为父数据。当我开始时,父数据的开头有这个奇怪的不可打印字符。它是供应商提供的数据,所以我无法控制它。我的问题是,在我将数据 sn-p 粘贴到父数据的中间之后,最终产品的开头除了最初开始的字符之外,还有一个 new 不可打印字符。这个新的不可打印字符既不在父数据中,也不在子数据 sn-p 中。我不知道它来自哪里,也不知道它是如何进入我的数据的。

我怀疑这是一个 XML::Twig 错误,因为在 while 循环中从文件句柄中读取一行时发生字符串损坏,但是当我删除 XML:: 时我没有成功地重新创建我的问题我的脚本中有 Twig 代码,所以我不得不把它留在里面。

这是我第一次尝试处理字符串中的不可打印字符。我是否需要做一些特别的事情而不是像对待普通字符串或其他东西一样对待它们?

我在 Windows XP 上使用 ActiveState Perl 5.10.1 和 XML::Twig 3.32(最新)和 Eclipse 3.5.1 IDE。

这是一个演示问题的脚本:

use strict; 
use warnings; 
use XML::Twig; 

my $FALSE = 0;
my $TRUE = 1;
my $name = 'KurtsProgram';
my $task = 'MainTask';
my $hidden_char = "\xBF";
my $data = $hidden_char . 
'(*********************************************
  Data-File-Header-Junk
**********************************************)

    PROGRAM MainProgram ()
    END_PROGRAM

    TASK SecondaryTask ()
    END_TASK

    TASK MainTask ()
        MainProgram;
    END_TASK
';
my $new_data = insertProgram( $name, $task, $data );

# test to see if results start out as expected
if ( $new_data =~ m/^\Q$hidden_char\E/ ) {
    print "SUCCESS\n";
}
else {
    print STDERR "ERROR: What happened?\n";
    print STDERR "ORIGINAL: \n$data\n";
    print STDERR "MODIFIED: \n$new_data\n";
}

sub insertProgram {
    my ( $local_name, $local_task, $local_data ) = @_;

    # get program section from XML template
    my $twig = new XML::Twig;
    $twig->parse( '<?xml version="1.0"?>
<TemplateSet>
    <PROGRAM>PROGRAM <Name>ProgramNameGoesHere</Name> ()
    END_PROGRAM</PROGRAM>
    <TASK>TASK <Name>TaskNameGoesHere</Name> ()
    END_TASK</TASK>
</TemplateSet>
' );   
    my $program = $twig->root->first_child('PROGRAM');

    # replace program name in XML template
    $program->first_child('Name')->set_text($local_name);
    my $insert = $program->text();

    # stick modified program into data
    if ( $local_data =~ s/(\s+PROGRAM\s+[^\s]+\s+\()/\n\n    $insert $1/ ) {
        # found it and inserted new program
    }
    else {
        # not found
        return;
    }

    # add program name to task list
    my $added_program_to_task = $FALSE;
    my $found_start = $FALSE;
    my $found_end = $FALSE;
    my $new_data = "";
    # open string as a filehandle for line by line processing
    my $filehandle;
    open( $filehandle, '<', \$local_data )
        or die("Can't open string as a filehandle: $!");
    while (defined (my $line = <$filehandle>)) {
        # look for start of our task
        if ( 
               ( !$found_start ) &&
               ( $line =~ m/\s+TASK\s+\Q$local_task\E\s+\(/ )
            ) {
            # found the task!
            $found_start = $TRUE;
        }

        # look for end of our task
        if (
                ( $found_start ) && ( !$found_end ) &&
                ( $line =~ m/\s+END_TASK/ )
            )
        {
            # found the end tag for the task section!
            $found_end = $TRUE;

            # add the program name to the bottom of the list
            $line = "        " . $local_name . ";\n" . $line;
            $added_program_to_task = $TRUE;
        }

        # compile new data from processed line or original line
        $new_data = $new_data . $line;
    }
    close($filehandle);

    if ($added_program_to_task) {
        # success
    }
    else {
        # unable to find task
        return;
    }

    return $new_data;
}

当我运行这个脚本时,我得到以下输出:

ERROR: What happened?
ORIGINAL: 
¿(*********************************************
      Data-File-Header-Junk
    **********************************************)

        PROGRAM MainProgram ()
        END_PROGRAM

        TASK SecondaryTask ()
        END_TASK

        TASK MainTask ()
            MainProgram;
        END_TASK

MODIFIED: 
¿(*********************************************
      Data-File-Header-Junk
    **********************************************)

        PROGRAM KurtsProgram ()
        END_PROGRAM 

        PROGRAM MainProgram ()
        END_PROGRAM

        TASK SecondaryTask ()
        END_TASK

        TASK MainTask ()
            MainProgram;
            KurtsProgram;
        END_TASK

您可以在 MODIFIED 中的 M 正下方看到添加到数据前面的额外字符。

【问题讨论】:

    标签: perl string corruption non-printable xml-twig


    【解决方案1】:

    它对字符进行了 ISO-8859-1 到 UTF-8 编码转换:\xBF -> \xC2\xBF

    XML::Twig 将其所有输入转换为 UTF-8 (see here)。

    您可以使用 keep_encoding 选项告诉 Twig 保留输入编码(另请参阅 XML::Twig 常见问题解答:My XML documents/data are produced by tools that do not grok Unicode, will XML::Twig help me there?)。

    但也许保留 UTF-8 会更好,或者静默删除该字符,具体取决于您要如何处理它。

    【讨论】:

    • 数据会直接返回到供应商的应用程序中,因此数据前面的特殊不可打印字符需要保持原样。
    • 在这种情况下,keep_encoding 应该可以完成这项工作。
    【解决方案2】:

    我无法真正理解您的代码,它仍然太复杂而无法快速调试,但问题可能与在开始时会被忽略的 BOM(参见 Unicode BOM FAQ)有关XML 文档,但如果您将它复制到另一个文档的中间就不会?只是因为 xBF 值而在这里猜测,这是 UTF-8 文档的 BOM 的一部分。

    【讨论】:

      猜你喜欢
      • 2021-11-09
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-04
      • 1970-01-01
      • 1970-01-01
      • 2012-11-09
      相关资源
      最近更新 更多