다음과 유사한 내용을 포함하는 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
쌍만 포함되어 있으므로 다음 과 같은 상황 은 불가능합니다.aaa
bbb
aaa
bbb
aaa
그렇다면 어떤 매개변수를 전달해야 하는지 제안해 주실 수 있나요 sed
? find
모든 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
블록이 백업 버퍼에 저장되고 출력에서 위치를 바꾸기 전에 두 번째 블록을 가져옵니다.
전자라면 블록의 위치에는 영향을 미치지 않습니다. 이러한 방식으로 일치하지 않는 쌍이 유지됩니다.
입력으로 주어진...
<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
당신이 처벌을 추구하는 사람이 아니라면 이것은 적합하지 않습니다 . 적어도 보다 일반적인 경우에는 블록이 한 줄 이상으로 시작됩니다(또는 태그가 여러 줄로 분할되는데, 이는 XML/HTML에서 가능합니다).
이 작업을 수행하기 위해 XML 파서 이외의 다른 것을 사용해야 하는 경우(예, 일반적으로 입력을 수정하거나 손상된 부분을 제거하는 것이 더 나은 생각입니다) awk
최소한 다음과 같은 것을 사용하십시오. 이러한 작업에 더 적합합니다 * ) . 일반적인 아이디어는 다음과 같습니다.
- 첫 번째 블록이 시작될 때까지 입력 줄을 인쇄합니다.
- 교환할 첫 번째 블록의 행을 누적합니다.
- 블록 사이에 라인을 축적합니다.
- 두 번째 블록의 행을 인쇄합니다.
- 3단계에서 쌓인 블록 사이의 줄을 인쇄합니다.
- 2단계에서 누적된 첫 번째 블록의 행을 인쇄합니다.
- 나머지를 인쇄하세요.
또한 확인하는 것을 잊지 마세요표준 SO Q&A.
* 내가 주장하는 이유: sed는 라인 지향적이고 단순함을 목표로 합니다(여행 비용은 변경될 수 있습니다.) 텍스트 변환. 이는 AWK(및 어느 정도 Perl)에서도 마찬가지지만 후자가 더 복잡한 스크립트를 작성하는 것이 더 간단합니다(여러 변수에 액세스하기 쉽고 필드로 자동 분할 등이 더 쉽습니다). 따라서 매우 잘 분리된 두 개의 청크만 교체해야 하고 다른 형식의 입력을 처리하기 위해 스크립트를 확장할 필요가 없다면 더 복잡한 언어가 아마도 더 나은 도구일 것입니다. 즉, Perl에는 모듈로 쉽게 사용할 수 있는 XML 파서가 있습니다.
답변4
정규식을 사용하여 HTML을 구문 분석하는 것은 분명히 권장되지 않습니다.
대신에 다음을 사용할 수 있습니다.길&xmlstarlet소스 파일이 유효한 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