Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Perl中从字符串中去除无效的XML字符?_Xml_Perl - Fatal编程技术网

如何在Perl中从字符串中去除无效的XML字符?

如何在Perl中从字符串中去除无效的XML字符?,xml,perl,Xml,Perl,我正在寻找一种标准的、经认可的、健壮的方法,在将字符串写入XML文件之前,从字符串中删除无效字符。我在这里说的是包含退格(^H)和换行符等的文本块 必须有一个标准的库/模块函数来执行此操作,但我找不到它 我正在使用它来构建DOM树,然后将其序列化到磁盘。如果您使用XML库来构建XML(而不是字符串连接、简单模板等),那么它应该为您解决这一问题。重新发明轮子是没有意义的 等 您可以使用正则表达式删除控制字符,例如\cH将与\cL或\x08和\x0C分别匹配backspace和Formfe

我正在寻找一种标准的、经认可的、健壮的方法,在将字符串写入XML文件之前,从字符串中删除无效字符。我在这里说的是包含退格(^H)和换行符等的文本块

必须有一个标准的库/模块函数来执行此操作,但我找不到它


我正在使用它来构建DOM树,然后将其序列化到磁盘。

如果您使用XML库来构建XML(而不是字符串连接、简单模板等),那么它应该为您解决这一问题。重新发明轮子是没有意义的


您可以使用正则表达式删除控制字符,例如\cH将与\cL或\x08和\x0C分别匹配backspace和Formfeed。

您可以使用一个简单的方法查找并替换文本块中的所有控制字符,将它们替换为空格或将它们全部删除-

# Replace all control characters with a space
$text =~ s/[[:cntrl:]]/ /g;

# or remove them
$text =~ s/[[:cntrl:]]//g;

几乎所有人都说过,使用正则表达式。老实说,它不够复杂,不值得添加到库中。使用替换对文本进行预处理

您对上述换行符的评论表明,格式对您来说非常重要,因此您可能需要准确地决定要用什么替换某些字符

XML规范中明确定义了无效字符列表(例如,这里)。不允许使用的字符是ASCII控制字符,包括回车、换行和制表符。因此,您将看到一个29个字符的正则表达式字符类。那当然不算太糟

比如:

$text =~ s/[\x00-\x08 \x0B \x0C \x0E-\x19]//g;
use HTML::Entities "encode_entities_numeric";
$encoded_string = encode_entities_numeric( $string, "\x00-\x08\x0B\x0C\x0E-\x19");
应该这样做。

Translate比regex替换快得多。特别是如果你想删除所有字符。使用牛顿集:

$string_to_clean =~ tr/\x00-\x08\x0B\x0C\x0E-\x19//d;
这样的测试:

cmpthese 1_000_000
       , { translate => sub { 
               my $copy = $text; 
               $copy =~ tr/\x00-\x08\x0B\x0C\x0E-\x19//d; 
           }
           , substitute => sub { 
               my $copy = $text; 
               $copy =~ s/[\x00-\x08\x0B\x0C\x0E-\x19]//g; 
           }
         };
是的:

                Rate substitute  translate
substitute  287770/s         --       -86%
translate  2040816/s       609%         --

我需要删除的字符越多,tr就越快。

我以前没有对包含“无效”字符的XML做过很多工作,但是 在我看来,这里有两个完全不同的问题

首先,数据中有一些您可能不需要的字符。您应该独立于任何XML限制来决定它们是什么以及如何删除/替换它们。例如,您可能有类似于
x^H\u y^H\u z^H\u的内容,您决定同时删除退格和以下字符。或者,事实上,您可能不想调整数据,但由于需要用XML表示数据而感到不得不这样做

更新:我为后代保留了以下段落,但它们基于一个误解:我认为只要编码正确,就可以在XML数据中包含任何字符,但似乎有些字符是完全多余的, 甚至编码?LibXML除去了这些字符(至少当前版本是这样),但nul字符除外,它将nul字符视为字符串的结尾,并丢弃它和以下任何字符:(

第二,您的数据中可能有需要用XML编码的字符。理想情况下,您使用的任何XML模块都可以为您做到这一点,但如果没有,您应该能够手动完成,例如:

$text =~ s/[\x00-\x08 \x0B \x0C \x0E-\x19]//g;
use HTML::Entities "encode_entities_numeric";
$encoded_string = encode_entities_numeric( $string, "\x00-\x08\x0B\x0C\x0E-\x19");

但这实际上只是权宜之计。使用适当的XML模块;例如,请参见。

好的,这似乎已经得到了回答,但这又有什么关系呢。如果你想创作XML文档,你必须使用XML库

#!/usr/bin/perl
use strict;
use XML::LibXML;

my $doc = XML::LibXML::Document->createDocument('1.0');
$doc->setURI('http://example.com/myuri');
$doc->setDocumentElement($doc->createElement('root-node'));

$doc->documentElement->appendTextChild('text-node',<<EOT);
    This node contains &, ñ, á, <, >...
EOT

print $doc->toString;
!/usr/bin/perl
严格使用;
使用XML::LibXML;
我的$doc=XML::LibXML::Document->createDocument('1.0');
$doc->setURI($doc)http://example.com/myuri');
$doc->setDocumentElement($doc->createElement('root-node'));

$doc->documentElement->appendTextChild('text-node',用于删除无效xml-1.0字符的完整正则表达式是:

# #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
$str =~ s/[^\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go;
对于xml-1.1,它是:

# allowed: [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
$str =~ s/[^\x01-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go;
# restricted:[#x1-#x8][#xB-#xC][#xE-#x1F][#x7F-#x84][#x86-#x9F]
$str =~    s/[\x01-\x08\x0B-\x0C\x0E-\x1F\x7F-\x84\x86-\x9F]//go;

我找到了一个解决方案,但它使用
iconv
命令而不是perl

$ iconv -c -f UTF-8 -t UTF-8 invalid.utf8 > valid.utf8

基于<强>正则表达式的上述解决方案不起作用!!< /强>,考虑下面的例子:

$ perl -e 'print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\x{A0}\x{A0}</root>"' > invalid.xml
$ perl -e 'use XML::Simple; XMLin("invalid.xml")'
invalid.xml:2: parser error : Input is not proper UTF-8, indicate encoding !
Bytes: 0xA0 0xA0 0x3C 0x2F
$ perl -ne 's/[^\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go; print' invalid.xml > valid.xml
$ perl -e 'use XML::Simple; XMLin("valid.xml")'
invalid.xml:2: parser error : Input is not proper UTF-8, indicate encoding !
Bytes: 0xA0 0xA0 0x3C 0x2F
$perl-e'print“\n\x{A0}\x{A0}”>无效的.xml
$perl-e“使用XML::Simple;XMLin(“invalid.XML”)”
无效。xml:2:解析器错误:输入不正确UTF-8,请指示编码!
字节:0xA0 0xA0 0x3C 0x2F
$perl-ne的/[^\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]///go;打印'invalid.xml>valid.xml
$perl-e“使用XML::Simple;XMLin(“valid.XML”)”
无效。xml:2:解析器错误:输入不正确UTF-8,请指示编码!
字节:0xA0 0xA0 0x3C 0x2F
事实上,这两个文件
invalid.xml
valid.xml
是相同的


问题是范围“\x20-\x{D7FF}”匹配这些unicode字符的有效表示,但不匹配无效字符序列“\x{A0}\x{A0}”。

Axeman关于使用tr的权利,但他和newt在反转XML规范的合法字符范围时犯了一个小错误

由于
\x20
之前的十六进制数是
\x1F
(而不是
\x19
!),您应该使用

$string_to_clean =~ tr/\x00-\x08\x0B\x0C\x0E-\x1F//d;

@David:这些库只是从传入字符串中剥离控制字符吗?据我所知,XML::LibXML除了在包含无效字符时拒绝外,对文本节点内容没有任何作用。如果其他库也这样做了,我会感到惊讶。newt,这就是首先使用XML库的意义。当然rse是的,但他问如何确保文本内容不包含无效字符,从而避免出现此问题。@newt:我不完全确定“此问题”是什么意思。我看到XML::LibXML去掉了“非法”字符,但nul除外,它将nul视为数据的结尾:(…这也会删除换行符-所以不是很有用:)哎哟,我没想到换行符。纽特的答案似乎对你要做的事情没问题。是的,这是