24

Perl で正規表現を使用して、すべてのタグを照合して削除する必要があります。私は次のものを持っています:

<\\??(?!p).+?>

</p>しかし、これは依然として終了タグと一致します。終了タグと一致させる方法についてのヒントはありますか?

これはxhtmlで実行されていることに注意してください。

4

14 に答える 14

38

正規表現の使用を主張する場合、ほとんどの場合、次のようなものが機能します。

# Remove all HTML except "p" tags
$html =~ s{<(?>/?)(?:[^pP]|[pP][^\s>/])[^>]*>}{}g;

説明:

s{
  <             # opening angled bracket
  (?>/?)        # ratchet past optional / 
  (?:
    [^pP]       # non-p tag
    |           # ...or...
    [pP][^\s>/] # longer tag that begins with p (e.g., <pre>)
  )
  [^>]*         # everything until closing angled bracket
  >             # closing angled bracket
 }{}gx; # replace with nothing, globally

しかし、実際には、いくつかの頭痛の種を避け、代わりにパーサーを使用してください。CPANには適切なモジュールがいくつかあります。非常に有能なHTML ::ParserCPANディストリビューションに付属するHTML::TokeParserモジュールを使用した例を次に示します。

use strict;

use HTML::TokeParser;

my $parser = HTML::TokeParser->new('/some/file.html')
  or die "Could not open /some/file.html - $!";

while(my $t = $parser->get_token)
{
  # Skip start or end tags that are not "p" tags
  next  if(($t->[0] eq 'S' || $t->[0] eq 'E') && lc $t->[1] ne 'p');

  # Print everything else normally (see HTML::TokeParser docs for explanation)
  if($t->[0] eq 'T')
  {
    print $t->[1];
  }
  else
  {
    print $t->[-1];
  }
}

HTML :: Parserは、ファイル名、開いているファイルハンドル、または文字列の形式で入力を受け入れます。上記のコードをライブラリにラップし、宛先を構成可能にする(つまり、print上記のように行うだけではない)ことは難しくありません。その結果、正規表現を使用するよりもはるかに信頼性が高く、保守が容易になり、場合によっては高速になります(HTML :: ParserはCベースのバックエンドを使用します)。

于 2008-08-27T12:31:35.513 に答える
16

私の意見では、HTML パーサー以外で HTML を解析しようとすることは、苦痛の世界を求めているだけです。HTML は非常に複雑な言語です (これが、HTML よりもはるかに単純な XHTML が作成された主な理由の 1 つです)。

たとえば、次のようになります。

<HTML /
  <HEAD /
    <TITLE / > /
    <P / >

完全で、100% 整形式で、100% 有効な HTML ドキュメントです。(まぁDOCTYPE宣言抜けてるけどそれ以外は…)

意味的には

<html>
  <head>
    <title>
      &gt;
    </title>
  </head>
  <body>
    <p>
      &gt;
    </p>
  </body>
</html>

しかし、それでも対処しなければならないのは有効な HTML です。もちろん、それを解析する正規表現を考案することもできますが、他の人がすでに示唆しているように、実際の HTML パーサーを使用する方がはるかに簡単です。

于 2008-08-27T14:01:27.530 に答える
14

私はこれを思いつきました:

<(?!\/?p(?=>|\s.*>))\/?.*?>

x/
<           # Match open angle bracket
(?!         # Negative lookahead (Not matching and not consuming)
    \/?     # 0 or 1 /
    p           # p
    (?=     # Positive lookahead (Matching and not consuming)
    >       # > - No attributes
        |       # or
    \s      # whitespace
    .*      # anything up to 
    >       # close angle brackets - with attributes
    )           # close positive lookahead
)           # close negative lookahead
            # if we have got this far then we don't match
            # a p tag or closing p tag
            # with or without attributes
\/?         # optional close tag symbol (/)
.*?         # and anything up to
>           # first closing tag
/

これは、属性の有無にかかわらず p タグと終了 p タグを処理するようになりましたが、属性の有無にかかわらず、前および類似のタグと一致します。

属性は取り除かれませんが、私のソース データには属性が含まれていません。これを行うために後でこれを変更する可能性がありますが、今のところはこれで十分です。

于 2008-08-27T11:26:12.957 に答える
4

なぜこれをしたいのかわからない - HTMLサニタイズのための正規表現が常に最良の方法であるとは限らない(属性などをサニタイズすることを覚えておく必要があり、 javascript: hrefs などを削除する必要がある)...しかし、HTMLに一致する正規表現ではないタグ<p></p>:

(<[^pP].*?>|</[^pP]>)

詳細:

(
    <               # < opening tag
        [^pP].*?    # p non-p character, then non-greedy anything
    >               # > closing tag
|                   #   ....or....
    </              # </
        [^pP]       # a non-p tag
    >               # >
)
于 2008-08-27T12:17:14.050 に答える
3

Xetius、言及されていない単純な解決策があったため、この古くからの質問を復活させました。(正規表現バウンティクエストの調査中にあなたの質問を見つけました。)

正規表現を使用して html を解析することに関するすべての免責事項があるので、これを行う簡単な方法を次に示します。

#!/usr/bin/perl
$regex = '(<\/?p[^>]*>)|<[^>]*>';
$subject = 'Bad html <a> </I> <p>My paragraph</p> <i>Italics</i> <p class="blue">second</p>';
($replaced = $subject) =~ s/$regex/$1/eg;
print $replaced . "\n";

このライブデモを見る

参照

状況 s1、s2、s3 以外でパターンを一致させる方法

パターンを一致させる方法...

于 2014-05-13T21:08:11.473 に答える
3

Xetius 正規表現を使用しましたが、正常に動作します。一部の flex 生成タグは例外で、
内部にスペースを入れずに : にすることができます。私は簡単にそれを修正しようとしましたか?\s の後、動作しているように見えます:

<(?!\/?p(?=>|\s?.*>))\/?.*?>

私はフレックス生成されたhtmlテキストからタグをクリアするためにそれを使用しているので、例外タグも追加しました:

<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>
于 2010-05-28T10:15:31.390 に答える
2

HTML は通常の言語ではないため、正規表現が HTML とのマッチングに優れているとは思えません。彼らはこのタスクを実行できるかもしれませんが (私には確信が持てませんが)、他の場所を探すことを検討します。perl には、HTML を操作するための既製のライブラリがいくつかあるはずです。

とにかく、私はあなたが一致させたいのは </?(p.+|.*)(\s*.*)> 貪欲ではないと思います (私はperlの正規表現構文の気まぐれを知らないので、私は助けることができませんさらに遠く)。\s は空白を意味すると仮定しています。おそらくそうではありません。いずれにせよ、タグ名から空白でオフセットされた属性と一致するものが必要です。しかし、エスケープされていない山かっこをスクリプトやコメント内に入れたり、照合したくない属性値を引用したりすることがよくあるため、それはそれよりも困難です。

ですから、私が言うように、正規表現がこの仕事に適したツールだとは本当に思いません。

于 2008-08-27T10:53:29.757 に答える
2

HTML は正規の言語ではないため、

HTML はそうではありませんが、HTML タグは正規表現で適切に記述できます。

于 2008-08-27T10:54:58.943 に答える
1

p タグの「p」の前に空白を許可することもできます。どのくらいの頻度でこれに遭遇するかはわかりませんが、 < p> は完全に有効な HTML です。

于 2008-08-27T13:11:04.547 に答える
1

元の正規表現は、ほとんど労力をかけずに機能させることができます。

 <(?>/?)(?!p).+?>

問題は /? (または \?) は、その後のアサーションが失敗したときに、一致したものをあきらめました。非バックトラッキング グループ (?>...) を使用すると、一致したスラッシュが解放されないように注意が払われるため、(?!p) アサーションは常にタグ テキストの先頭に固定されます。

(とは言っても、一般的に正規表現を使用して HTML を解析することは適切ではないことに同意します)。

于 2008-09-19T09:26:46.187 に答える
1

これが、PERL 互換の構文を使用すると主張する言語と同様に、PERL でも機能すると仮定すると、次のようになります。

/<\/?[^p][^>]*>/

編集:

残念ながら、それは<pre>orタグと一致しません。<param>

これ、もしかして?

/<\/?(?!p>|p )[^>]+>/

<p>属性を持つタグもカバーする必要があります。

于 2008-08-27T10:45:36.190 に答える
0

これを試してください、うまくいくはずです:

/<\/?([^p](\s.+?)?|..+?)>/

説明: これは、「p」を除く 1 文字の後にオプションの空白とその他の文字が続くか、複数の文字 (少なくとも 2 つ) のいずれかと一致します。

p/編集:タグで属性を処理する機能を追加しました。

于 2008-08-27T10:47:17.697 に答える
-1

悪い人が次のようなことをする可能性があるため、おそらく <p> タグの属性も削除する必要があります。

<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>

これを行う最も簡単な方法は、ここで提案されている正規表現を使用して、属性を持つ <p> タグを検索し、それらを属性のない <p> タグに置き換えることです。安全な側にいるだけです。

于 2008-08-27T11:13:39.647 に答える