免責事項:
他の人が指摘するか、すでに指摘しているように、正規表現を使用して非正規言語を解析することは危険をはらんでいます! 特に HTML のタグ スープを解析する場合は、そのジョブ専用に設計された専用のパーサーを使用することをお勧めします。
それは言った...
どうしても正規表現を使用したい場合は、正規表現ソリューションを実装したテスト済みの PHP スクリプトを次に示します。これは「かなり良い」仕事をします。
<?php // test.php Rev:20120626_2100
function strip_html_anchor_tags_not_having_class($text) {
$re_html_anchor_not_having_class ='% # Rev:20120626_1300
# Match an HTML 4.01 A element NOT having a specific class.
<a\b # Anchor element start tag open delimiter
(?: # Zero or more attributes before CLASS.
\s+ # Attributes are separated by whitespace.
(?!class\b) # Only non-CLASS attributes here.
[A-Za-z][\w\-:.]* # Attribute name is required.
(?: # Attribute value is optional.
\s*=\s* # Name and value separated by =
(?: # Group for value alternatives.
"[^"]*" # Either a double-quoted string,
| \'[^\']*\' # or a single-quoted string,
| [\w\-:.]+ # or a non-quoted string.
) # End group of value alternatives.
)? # Attribute value is optional.
)* # Zero or more attributes before CLASS.
(?: # Optional CLASS (but only if NOT MyClass).
\s+ # CLASS attribute is separated by whitespace.
class # (case insensitive) CLASS attribute name.
\s*=\s* # Name and value separated by =
(?: # Group allowable CLASS value alternatives.
(?-i) # Use case-sensitive match for CLASS value.
" # Either a double-quoted value...
(?: # Single-char-step through CLASS value.
(?! # Assert each position is NOT MyClass.
(?<=["\s]) # Preceded by opening quote or space.
MyClass # (case sensitive) CLASS value to NOT be matched.
(?=["\s]) # Followed by closing quote or space.
) # End assert each position is NOT MyClass.
[^"] # Safe to match next CLASS value char.
)* # Single-char-step through CLASS value.
" # Ok. DQ value does not contain MyClass.
| \' # Or a single-quoted value...
(?: # Single-char-step through CLASS value.
(?! # Assert each position is NOT MyClass.
(?<=[\'\s]) # Preceded by opening quote or space.
MyClass # (case sensitive) CLASS value to NOT be matched.
(?=[\'\s]) # Followed by closing quote or space.
) # End assert each position is NOT MyClass.
[^\'] # Safe to match next CLASS value char.
)* # Single-char-step through CLASS value.
\' # Ok. SQ value does not contain MyClass.
| # Or a non-quoted, non-MyClass value...
(?! # Assert this value is NOT MyClass.
MyClass # (case sensitive) CLASS value to NOT be matched.
) # Ok. NQ value is not MyClass.
[\w\-:.]+ # Safe to match non-quoted CLASS value.
) # End group of allowable CLASS values.
(?: # Zero or more attribs allowed after CLASS.
\s+ # Attributes are separated by whitespace.
[A-Za-z][\w\-:.]* # Attribute name is required.
(?: # Attribute value is optional.
\s*=\s* # Name and value separated by =
(?: # Group for value alternatives.
"[^"]*" # Either a double-quoted string,
| \'[^\']*\' # or a single-quoted string,
| [\w\-:.]+ # or a non-quoted string.
) # End group of value alternatives.
)? # Attribute value is optional.
)* # Zero or more attributes after CLASS.
)? # Optional CLASS (but only if NOT MyClass).
\s* # Optional whitespace before closing >
> # Anchor element start tag close delimiter
( # $1: Anchor element contents.
[^<]* # {normal*} Zero or more non-<
(?: # Begin {(special normal*)*} construct
< # {special} Allow a < but only if
(?!/?a\b) # not the start of the </a> close tag.
[^<]* # more {normal*} Zero or more non-<
)* # Finish {(special normal*)*} construct
) # End $1: Anchor element contents.
</a\s*> # A element close tag.
%ix';
// Remove all matching start and end tags but keep the element contents.
return preg_replace($re_html_anchor_not_having_class, '$1', $text);
}
$input = file_get_contents('testdata.html');
$output = strip_html_anchor_tags_not_having_class($input);
file_put_contents('testdata_out.html', $output);
?>
function strip_html_anchor_tags_not_having_class($text)
この関数は、以下を含む特定の (大文字と小文字を区別する)属性値を<A>
持たないすべての HTML 4.01 アンカー要素 (つまり、タグ) の開始タグと一致する終了タグを取り除きます。値には任意の数の値を含めることができますが、そのうちの 1 つが正確に: である必要があります。アンカー タグ名と CLASS 属性名は、大文字と小文字を区別せずに照合されます。CLASS
MyClass
CLASS
MyClass
入力例 ( testdata.html
):
<h2>Paragraph contains links to be preserved (CLASS has "MyClass"):</h2>
<p>
Single DQ matching CLASS: <a href="URL" class="MyClass">Test 01</a>.
Single SQ matching CLASS: <a href="URL" class='MyClass'>Test 02</a>.
Single NQ matching CLASS: <a href="URL" class=MyClass>Test 03</a>.
Variable whitespace: <a href = "URL" class = MyClass >Test 04</a>.
Variable capitalization: <A HREF = "URL" CLASS = "MyClass" >Test 04</A>.
Reversed attribute order: <a class="MyClass" href="URL">Test 05</a>
Class before MyClass: <a href="URL" class="Pre MyClass">Test 06</a>.
Class after MyClass: <a href="URL" class="MyClass Post">Test 07</a>.
Sandwiched MyClass: <a href="URL" class="Pre MyClass Post">Test 08</a>.
Link with HTML content: <a class="MyClass" href="URL"><b>Test</b> 09</a>.
</p>
<h2>Paragraph contains links to be stripped (NO CLASS with "MyClass"):</h2>
<p>
Case does not match: <a href="URL" class="myclass">TEST 10</a>.
CLASS not whole word: <a href="URL" class="NotMyClass">TEST 11</a>.
No class attribute: <a href="URL">TEST 12</a>.
Link with HTML content: <a class="NotMyClass" href="URL"><b>Test</b> 13</a>.
</p>
出力例 ( testdata_out.html
):
<h2>Paragraph contains links to be preserved (CLASS has "MyClass"):</h2>
<p>
Single DQ matching CLASS: <a href="URL" class="MyClass">Test 01</a>.
Single SQ matching CLASS: <a href="URL" class='MyClass'>Test 02</a>.
Single NQ matching CLASS: <a href="URL" class=MyClass>Test 03</a>.
Variable whitespace: <a href = "URL" class = MyClass >Test 04</a>.
Variable capitalization: <A HREF = "URL" CLASS = "MyClass" >Test 04</A>.
Reversed attribute order: <a class="MyClass" href="URL">Test 05</a>
Class before MyClass: <a href="URL" class="Pre MyClass">Test 06</a>.
Class after MyClass: <a href="URL" class="MyClass Post">Test 07</a>.
Sandwiched MyClass: <a href="URL" class="Pre MyClass Post">Test 08</a>.
Link with HTML content: <a class="MyClass" href="URL"><b>Test</b> 09</a>.
</p>
<h2>Paragraph contains links to be stripped (NO CLASS with "MyClass"):</h2>
<p>
Case does not match: TEST 10.
CLASS not whole word: TEST 11.
No class attribute: TEST 12.
Link with HTML content: <b>Test</b> 13.
</p>
正規表現をさらに発展させたい読者は、この (かなり長くて複雑な) 正規表現を研究することをお勧めします。正確さと速度の両方のために慎重に手作りされており、いくつかの高度な効率化技術を実装しています。もちろん、単なる人間が読めるように完全にコメントされています。この例は、「REGULAR EXPRESSIONS」がリッチな (非REGULAR ) プログラミング言語に進化したことを明確に示しています。
このソリューションが失敗するエッジ ケースが常にあることに注意してください。たとえば、CDATA セクション、コメント、スクリプト、スタイル、およびタグ属性値内の悪意のある文字列は、これを引き起こす可能性があります。(上記の免責事項を参照してください。) とはいえ、このソリューションは多くの場合に非常にうまく機能します (ただし、100% 信頼できるわけではありません!) 。