perl正则表达式以& #xx;形式替换不可打印的字符;

时间:2014-08-31 14:32:42

标签: xml regex perl

XML字符集仅限于以下内容:

[\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]

实体不得用于表示此集之外的字符。

我正在使用XML :: DOM从外部源解析一些XML数据文件。某些XML文件具有以& #xx;形式编码的不可打印字符。 (例如。)导致解析器崩溃,因为它们无效。我试图找到一种简单的方法来删除这些无效字符。我试过了

$xml =~ s/(&#\c\c;)//g;

似乎不起作用。所以似乎没有任何相关的东西,我一直在网上搜索一段时间没有成功。

4 个答案:

答案 0 :(得分:2)

我建议明确指定要删除的字符。

以下删除ascii范围中的不可打印字符实体。如果您想要覆盖所有不可打印的实体,就可以轻松扩展它。

另外,请注意@ikegami在问题评论中提到使用这样的正则表达式将破坏CDATA部分的内容。

use strict;
use warnings;

my $data = do {local $/; <DATA>};

# Allowed entities:
# [\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]

# Decimal Character Entities
$data =~ s/&#0*(?!(?:9|1[03])\b)(?:[12]?[0-9]|3[01]);//g;

# Hex Character Entities
$data =~ s/&#x0*(?![9ADad]\b)1?[[:xdigit:]];//g;

print $data;

__DATA__
<?xml version="1.0" encoding="UTF-8" ?> 
<root>
    <hex_character_entities>
        <hex00>&#x00;&#x01;&#x02;&#x03;&#x04;&#x05;&#x06;&#x07;&#x08;&#x09;&#x0A;&#x0B;&#x0C;&#x0D;&#x0E;&#x0F;</hex00>
        <hex10>&#x10;&#x11;&#x12;&#x13;&#x14;&#x15;&#x16;&#x17;&#x18;&#x19;&#x1A;&#x1B;&#x1C;&#x1D;&#x1E;&#x1F;</hex10>
        <hex20>&#x20;&#x21;...</hex20>
    </hex_character_entities>
    <decimal_character_entities>
        <dec00>&#00;&#01;&#02;&#03;&#04;&#05;&#06;&#07;&#08;&#09;</dec00>
        <dec10>&#10;&#11;&#12;&#13;&#14;&#15;&#16;&#17;&#18;&#19;</dec10>
        <dec20>&#20;&#21;&#22;&#23;&#24;&#25;&#26;&#27;&#28;&#29;</dec20>
        <dec30>&#30;&#31;&#32;&#33;...</dec30>
    </decimal_character_entities>
</root>

输出:

<?xml version="1.0" encoding="UTF-8" ?> 
<root>
    <hex_character_entities>
        <hex00>&#x09;&#x0A;&#x0D;</hex00>
        <hex10></hex10>
        <hex20>&#x20;&#x21;...</hex20>
    </hex_character_entities>
    <decimal_character_entities>
        <dec0>&#09;</dec0>
        <dec1>&#10;&#13;</dec1>
        <dec2></dec2>
        <dec3>&#32;&#33;...</dec3>
    </decimal_character_entities>
</root>

答案 1 :(得分:2)

编写一个查找HTML中所有实体并使用/e修饰符的子目录是有意义的,这样替换字符串就可以通过一个Perl代码块来提供。

此示例根据您自己的问题创建$html_chars正则表达式模式,该模式将检查任何单个字符是否在范围内,然后使用它来测试字符串中所有字符实体的值。

请注意,由于#修饰符允许空格和注释使正则表达式更具可读性,因此必须对模式中的哈希/x进行转义。

我的测试字符串使用十进制和十六进制中所有ASCII字符代码的实体,您可以看到替换只删除除HT,LF和CR之外的控制字符。

use strict;
use warnings;

my $html_chars = qr/[\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/;

my $html = do {
   local $/;
   <DATA>;
};

$html =~ s{ ( &\# ( x[0-9A-Z]+ | [0-9]+ ) ; ) } {
   my ($entity, $code) = ($1, $2);
   $code = hex $code if $code =~ s/x//i;
   chr($code) =~ $html_chars ? $entity : '';
}eixg;

print $html;

__DATA__

Decimal
&#0;&#1;&#2;&#3;&#4;&#5;&#6;&#7;&#8;&#9;&#10;&#11;&#12;&#13;&#14;&#15;
&#16;&#17;&#18;&#19;&#20;&#21;&#22;&#23;&#24;&#25;&#26;&#27;&#28;&#29;&#30;&#31;
&#32;&#33;&#34;&#35;&#36;&#37;&#38;&#39;&#40;&#41;&#42;&#43;&#44;&#45;&#46;&#47;
&#48;&#49;&#50;&#51;&#52;&#53;&#54;&#55;&#56;&#57;&#58;&#59;&#60;&#61;&#62;&#63;
&#64;&#65;&#66;&#67;&#68;&#69;&#70;&#71;&#72;&#73;&#74;&#75;&#76;&#77;&#78;&#79;
&#80;&#81;&#82;&#83;&#84;&#85;&#86;&#87;&#88;&#89;&#90;&#91;&#92;&#93;&#94;&#95;
&#96;&#97;&#98;&#99;&#100;&#101;&#102;&#103;&#104;&#105;&#106;&#107;&#108;&#109;&#110;&#111;
&#112;&#113;&#114;&#115;&#116;&#117;&#118;&#119;&#120;&#121;&#122;&#123;&#124;&#125;&#126;&#127;

Hex
&#x00;&#x01;&#x02;&#x03;&#x04;&#x05;&#x06;&#x07;&#x08;&#x09;&#x0A;&#x0B;&#x0C;&#x0D;&#x0E;&#x0F;
&#x10;&#x11;&#x12;&#x13;&#x14;&#x15;&#x16;&#x17;&#x18;&#x19;&#x1A;&#x1B;&#x1C;&#x1D;&#x1E;&#x1F;
&#x20;&#x21;&#x22;&#x23;&#x24;&#x25;&#x26;&#x27;&#x28;&#x29;&#x2A;&#x2B;&#x2C;&#x2D;&#x2E;&#x2F;
&#x30;&#x31;&#x32;&#x33;&#x34;&#x35;&#x36;&#x37;&#x38;&#x39;&#x3A;&#x3B;&#x3C;&#x3D;&#x3E;&#x3F;
&#x40;&#x41;&#x42;&#x43;&#x44;&#x45;&#x46;&#x47;&#x48;&#x49;&#x4A;&#x4B;&#x4C;&#x4D;&#x4E;&#x4F;
&#x50;&#x51;&#x52;&#x53;&#x54;&#x55;&#x56;&#x57;&#x58;&#x59;&#x5A;&#x5B;&#x5C;&#x5D;&#x5E;&#x5F;
&#x60;&#x61;&#x62;&#x63;&#x64;&#x65;&#x66;&#x67;&#x68;&#x69;&#x6A;&#x6B;&#x6C;&#x6D;&#x6E;&#x6F;
&#x70;&#x71;&#x72;&#x73;&#x74;&#x75;&#x76;&#x77;&#x78;&#x79;&#x7A;&#x7B;&#x7C;&#x7D;&#x7E;&#x7F;

<强>输出

Decimal
&#9;&#10;&#13;

&#32;&#33;&#34;&#35;&#36;&#37;&#38;&#39;&#40;&#41;&#42;&#43;&#44;&#45;&#46;&#47;
&#48;&#49;&#50;&#51;&#52;&#53;&#54;&#55;&#56;&#57;&#58;&#59;&#60;&#61;&#62;&#63;
&#64;&#65;&#66;&#67;&#68;&#69;&#70;&#71;&#72;&#73;&#74;&#75;&#76;&#77;&#78;&#79;
&#80;&#81;&#82;&#83;&#84;&#85;&#86;&#87;&#88;&#89;&#90;&#91;&#92;&#93;&#94;&#95;
&#96;&#97;&#98;&#99;&#100;&#101;&#102;&#103;&#104;&#105;&#106;&#107;&#108;&#109;&#110;&#111;
&#112;&#113;&#114;&#115;&#116;&#117;&#118;&#119;&#120;&#121;&#122;&#123;&#124;&#125;&#126;&#127;

Hex
&#x09;&#x0A;&#x0D;

&#x20;&#x21;&#x22;&#x23;&#x24;&#x25;&#x26;&#x27;&#x28;&#x29;&#x2A;&#x2B;&#x2C;&#x2D;&#x2E;&#x2F;
&#x30;&#x31;&#x32;&#x33;&#x34;&#x35;&#x36;&#x37;&#x38;&#x39;&#x3A;&#x3B;&#x3C;&#x3D;&#x3E;&#x3F;
&#x40;&#x41;&#x42;&#x43;&#x44;&#x45;&#x46;&#x47;&#x48;&#x49;&#x4A;&#x4B;&#x4C;&#x4D;&#x4E;&#x4F;
&#x50;&#x51;&#x52;&#x53;&#x54;&#x55;&#x56;&#x57;&#x58;&#x59;&#x5A;&#x5B;&#x5C;&#x5D;&#x5E;&#x5F;
&#x60;&#x61;&#x62;&#x63;&#x64;&#x65;&#x66;&#x67;&#x68;&#x69;&#x6A;&#x6B;&#x6C;&#x6D;&#x6E;&#x6F;
&#x70;&#x71;&#x72;&#x73;&#x74;&#x75;&#x76;&#x77;&#x78;&#x79;&#x7A;&#x7B;&#x7C;&#x7D;&#x7E;&#x7F;

答案 2 :(得分:0)

试试这个。

$ xml = ~s {&amp;#[0-9a-z] {1-2};} {} igs;

答案 3 :(得分:-1)

我会尝试使用\w代替\c

以下为我生成了正确的结果:

my $xml = <<XML;
<?xml version="1.0" encoding="UTF-8" ?> 
<outer>
  <inner>&#15;</inner>
</outer>
XML

$xml =~ s/&#\w{2};//g;