Sed/awk 正規表現: XML フィード

Sed/awk 正規表現: XML フィード

特定の正規表現を探していますが、3日間努力しましたが、正しい答えが見つかりませんでした。

XMLフィードの特定の部分を削除する必要があります。 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_elementXML要素が開かれるたびに呼び出されます。問題の要素がその要素であることを確認してください<description>。その場合は、フラグを設定します(そして追加の処理をスーパークラスに渡します)。
    • sub end_elementXML要素が閉じられるたびに呼び出されます。問題の要素がその要素<description>であることを確認してください。その場合、フラグをクリアして追加の処理をスーパークラスに渡します。
    • sub charactersテキストまたはCDATA要素が処理されるたびに呼び出されます。このサブルーチンはフラグが設定されていることを確認します。そうであれば、渡されたデータに正規表現を適用して不完全な文を削除します(点としてのみ計算します。この正規表現の改善は練習として読者に残ります)。 -血)
  • このmainパッケージにはスクリプトの開始点が含まれています。
    • 1つを設定しXML::SAX::Writer(デフォルトで標準出力であるXML形式に戻される解析されたXMLデータを出力します)、それをフィルタにリンクします(作成者に渡されたXMLデータには渡されたXMLデータが含まれます)。受信され、不完全な文は削除されます)フィルタは、を使用して生成されたXMLパーサにリンクされますXML::SAX::ParserFactory
    • その後、チェーン全体が入力として渡されます(という名前のファイルにあると仮定input.xml)。

これが複雑に見えたら、そうだからです。選択肢がある場合は、XMLを使用せず、JSONやYAMLなどのより簡単なものを使用してください;-)

関連情報