sedを使用して複数のファイルのHTMLブロック全体を交換する方法

sedを使用して複数のファイルのHTMLブロック全体を交換する方法

次のようなコンテンツを含むHTMLページがたくさんあります。

<div class="wrapper">

<div class="aaa">
...lot of html1 here like div's/spans etc..
</div> <!-- end aaa -->

<div class="bbb">
...lot of html2 here
</div><!-- end bbb -->

</div>

divをそのコンテンツと共にaaaクラスとbbbクラスに完全に置き換える必要があります。

だからそれは次のようになります:

<div class="wrapper">

<div class="bbb">
...lot of html2 here
</div><!-- end bbb -->

<div class="aaa">
...lot of html1 here
</div> <!-- end aaa -->

</div>

メモ:

1) ブロック間の空行はオプションです。 2)HTMLには正確なandペア
のみが含まれているため、次のような状況は不可能です。aaabbbaaabbbaaa

それでは、どのパラメータを渡すべきかを提案できますかsedfindすべてのHTMLファイルを見つけて、sed実行パラメータとして実行するために使用します。

find . -iname "*.html" -exec sed -i '' 's/WHAT IS HERE / AND HERE /g' {} \;

これはできませんが、sed可能であるとしましょう。awkあなたの期待を達成するための最善の方法についてあなたの考えを共有していただきありがとうございます。

修正する:

以下は実際のケースへのリンクです。 http://pastebin.com/mdhJ9rtL

答え1

aaa前の部分をbbb後ろに置くには、次の手順を実行します。

sed -i '/<div class="aaa">/{
        :1
        /<\/div> <\!-- end aaa -->/!{N;b 1}
        /<\/div> <\!-- end aaa -->/{N;h}
        d}
        /<\/div><\!-- end bbb -->/{n;G}' *html

答え2

ここに別のものがありますsed

sed '/.*<div class="...">.*/{ h;s///;x;:n
     /<.div>/!N;/<!-- end/x;/<.div>/x;//!bn
    s/\(.*\).\(<div class=.*>\).*/\2\1/;x
     /<.div>[^>]*$/s/.//;H;x
}'

行で始まり、class=.???.できるだけ多くのブロックを通過します。各ペアごとに位置が変わります。以下はいくつかの例です。

sed一致する行が見つかった場合:

<div class=".\{3\}">

H...ファイルの読み込み中に前のスペースが完全に消去されたことを確認し、一致する行に遭遇するまで各行のインポートを開始します。

<.div>

...そして...

<!-- end

...または電子かもしれません。両方が一致した場合、sedブロックはバックアップバッファに格納され、出力の位置を置き換える前に2番目のブロックを取得します。

電子ならブロックの位置には影響しません。このように、一致しないペアが維持される。

入力として与えられます...

<div class="wrapper">
<div class="aaa"> first </div> <!-- end aaa -->
between
<div class="bbb"> swap two </div> <!-- end bbb -->
blocks
<div class="ccc"> mismatched </div> <!-- end ccc --> 
the end         
</div>

印刷されます...

<div class="wrapper">
<div class="bbb"> swap two </div> <!-- end bbb -->
between
<div class="aaa"> first </div> <!-- end aaa -->
blocks
<div class="ccc"> mismatched </div> <!-- end ccc -->
the end
</div>

...与えられた場合:

<div class="wrapper">
<div class="aaa"> first </div> <!-- end aaa -->
between
<div class="bbb"> swap two </div> <!-- end bbb -->
blocks
<div class="ccc"> matched </div> <!-- end ccc --> 
the end
<div class="ddd"> now matched </div> <!-- end ddd -->
</div>

印刷されます...

<div class="wrapper">
<div class="bbb"> swap two </div> <!-- end bbb -->
between
<div class="aaa"> first </div> <!-- end aaa -->
blocks
<div class="ddd"> now matched </div> <!-- end ddd -->
the end
<div class="ccc"> matched </div> <!-- end ccc -->
</div>

<div class=そして、スペースを節約するためにこの例をこのように圧縮しましたが、始めと部分が同じ行にあるかどうかは<.div> <!-- end実際には重要ではありません。

<div class="wrapper">
<div class="aaa">

the first
block is here

</div> <!-- end aaa -->

these lines were
between aaa and bbb

<div class="bbb">

this is the second block
it should be swapped with the first

</div> <!-- end bbb -->

more
blocks
follow

<div class="ccc"> this is matched </div> <!-- end ccc -->
not the end
<div class="ddd">

this last block
is matched with the ccc line
</div> <!-- end ddd -->

this is the end
</div>

得る...

<div class="wrapper">
<div class="bbb"> 

this is the second block
it should be swapped with the first

</div> <!-- end bbb -->

these lines were
between aaa and bbb

<div class="aaa"> 

the first
block is here

</div> <!-- end aaa -->

more
blocks
follow

<div class="ddd"> 

this last block
is matched with the ccc line
</div> <!-- end ddd -->
not the end
<div class="ccc"> this is matched </div> <!-- end ccc -->

this is the end
</div>

答え3

sedあなたが罰を求めている人ではない場合、これは適切ではありません。少なくともより一般的な場合、ブロックは1行以上で始まります(またはタグは複数行に分割されます。これはXML / HTMLで可能です)。

これを行うには、XMLパーサー以外のものを使用する必要がある場合(通常、入力を変更したり破損した部分を削除したりする方が良い考えです)、awk少なくとも次のようなものを使用してください。これらの作業に適しています*)。一般的なアイデアは次のとおりです。

  1. 最初のブロックが始まるまで入力行を印刷します。
  2. 交換する最初のブロックの行を累積します。
  3. ブロック間に線を蓄積します。
  4. 2番目のブロックの行を印刷します。
  5. 手順3で積み重ねたブロック間の行を印刷します。
  6. ステップ2で累積された最初のブロックの行を印刷します。
  7. 残りを印刷してください。

また、確認することを忘れないでください標準SO Q&A

*私が主張する理由:sedはライン指向でシンプルさを目指しています(旅行費用は変更されることがあります。)テキスト変換。これはAWK(およびある程度Perl)でも同様ですが、後者はより複雑なスクリプトを書くのがより簡単です(複数の変数にアクセスしやすく、フィールドに自動分割などが簡単です)。したがって、非常によく分離された2つのチャンクのみを置き換える必要があり、他の形式の入力を処理するためにスクリプトを拡張する必要がない場合、より複雑な言語はおそらくより良いツールです。つまり、Perlにはモジュールとして簡単に使用できるXMLパーサーがあります。

答え4

正規表現を使用してHTMLを解析することは明らかにお勧めできません。

代わりに、次のものを使用できます。&ソースファイルが有効なXHTMLの場合:

xmlstarlet edit -L -u "//div[@class='a']" -v 'some inner HTML' file.xhtml

有効なXHTMLでない場合は、次のPerlコードを修正してみてください。

use strict;
use warnings;
use 5.008;

use File::Slurp 'read_file';
use HTML::TreeBuilder;

sub replace_keyword
{
  my $elt = shift;

  return if $elt->is_empty;

  $elt->normalize_content;      # Make sure text is contiguous

  my $content = $elt->content_array_ref;

  for (my $i = 0; $i < @$content; ++$i) {
    if (ref $content->[$i]) {
      # It's a child element, process it recursively:
      replace_keyword($content->[$i])
          unless $content->[$i]->tag eq 'a'; # Don't descend into <a>
    } else {
      # It's text:
      if ($content->[$i] =~ /here/) { # your keyword or regexp here
        $elt->splice_content(
          $i, 1, # Replace this text element with...
          substr($content->[$i], 0, $-[0]), # the pre-match text
          # A hyperlink with the keyword itself:
          [ a => { href => 'http://example.com' },
            substr($content->[$i], $-[0], $+[0] - $-[0]) ],
          substr($content->[$i], $+[0])   # the post-match text
        );
      } # end if text contains keyword
    } # end else text
  } # end for $i in content index
} # end replace_keyword


my $content = read_file('foo.shtml');

# Wrap the SHTML fragment so the comments don't move:
my $html = HTML::TreeBuilder->new;
$html->store_comments(1);
$html->parse("<html><body>$content</body></html>");

my $body = $html->look_down(qw(_tag body));
replace_keyword($body);

# Now strip the wrapper to get the SHTML fragment back:
$content = $body->as_HTML;
$content =~ s!^<body>\n?!!;
$content =~ s!</body>\s*\z!!;

次から借りるhttps://stackoverflow.com/questions/3900870/how-can-i-modify-html-files-in-perl

関連情報