Sed/awk 正则表达式:XML 提要

Sed/awk 正则表达式:XML 提要

我正在寻找一个特定的正则表达式,我尝试了三天,但没有找到正确的答案。

我需要删除 xml feed 的特定部分,我尝试使用 sed、awk,但它无法正常工作。

我拥有的 :

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier. Nommée FontCode, cette idée est <a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news

我需要的 :

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier.<a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news
  • 选择“<\description></description>之间的多个实例
  • 删除最后一句不完整的句子(在 href 之前,“Nommée FontCode, cette idée est ”)

感谢您的帮助 ! ;)

答案1

sed -E '/^[[:blank:]]*<description><!\[CDATA\[/s/([!?.])[^!?.<]*<a/\1 <a/' file

这将查找以确切字符串开头的所有行<description><![CDATA[(前面可能有空格或制表符)。在这些行上,将执行替换。

替换匹配句子终止符 ( [!?.]) 后跟任意数量的字符不是句子终止符 或<,以及字符串<a。这将被第一个句子终止符、空格和字符串 替换<a

答案2

我通过下面的 sed 命令进行了测试,它对我来说效果很好

 sed "s/particulier\..*<a/particulier.<a/g" file

输出

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier.<a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news

答案3

虽然 XML 是纯文本格式,但尝试使用 sed 和/或 awk 操作它是一个糟糕的主意,因为该格式在使用方式上有很多极端情况和异常,因此您应该将其视为二进制文件恰好可以用肉眼读取的格式而不是文本格式。这看起来很容易,直到你真正尝试一下。简短的回答是,不要。

相反,我建议使用具有处理 XML 库的脚本语言。这样的库有很多。在 Perl 中,您可以按照以下方式做一些事情:

#!/usr/bin/perl -wCSDA
use strict;
use warnings;

package MyFilter;
use base qw(XML::SAX::Base);

sub new {
    my $class = shift;
    my @args = @_;
    my $self = $class->SUPER::new(@args);

    $self->{indesc} = 0;
    return $self;
}

sub start_element {
    my $self = shift;
    my $data = shift;
    if ($data->{LocalName} eq "description") {
        $self->{indesc} = 1;
    }
    return $self->SUPER::start_element($data);
}

sub end_element {
    my $self = shift;
    my $data = shift;
    if ($data->{LocalName} eq "description") {
        $self->{indesc} = 1;
    }
    return $self->SUPER::end_element($data);
}

sub characters {
    my $self = shift;
    my $data = shift;
    if(($self->{indesc}) == 1) {
        $data->{Data} =~ s/\.[^\.]*<a href/.<a href/;
    }
    return $self->SUPER::characters($data);
}

package main;

use XML::SAX::ParserFactory;
use XML::SAX::Writer;

my $writer = XML::SAX::Writer->new();

my $filter = MyFilter->new(Handler => $writer);

my $input = XML::SAX::ParserFactory->parser(Handler => $filter);

$input->parse_uri("input.xml");

其工作原理如下:

  • package MyFilter;行表示一个实现 XML::SAX 过滤器的类:
    • sub new是构造函数,它实际上只创建$self->{indesc}标志。
    • sub start_element每次打开 XML 元素时都会被调用。我们检查所讨论的元素是否是该<description>元素;如果是这样,我们设置标志(并将进一步处理传递给超类)。
    • sub end_element每次关闭 XML 元素时都会被调用。我们检查所讨论的元素是否是该<description>元素;如果是这样,我们清除该标志(并将进一步处理传递给超类)。
    • sub characters每次处理文本或 CDATA 元素时都会调用。在该子程序中,我们检查标志是否已设置;如果是,我们对传递的数据应用正则表达式,以便删除任何不完整的句子(仅从点开始计数;此正则表达式的改进留给读者作为练习;-P)
  • main包包含脚本的起点:
    • 它设置一个XML::SAX::Writer(它只是输出解析后的 XML 数据,它再次以 XML 格式传递,默认情况下为标准输出),将其挂接到我们的过滤器(因此传递给编写器的 XML 数据包含过滤器所传递的 XML 数据)收到并删除了不完整的句子),并将过滤器连接到使用 . 创建的 XML 解析器XML::SAX::ParserFactory
    • 然后将整个链传递给输入(假设可以在名为 的文件中找到它input.xml)。

如果这看起来很复杂,那是因为事实确实如此。如果您有选择,就对 XML 说不,而使用更简单的东西,例如 JSON 或 YAML ;-)

相关内容