Tags analysieren
Reguläre Ausdrücke lösen auch komplexe Strukturen auf, mit ihrer Hilfe kann ich eine ganze HTML Datei analysieren. Ich kann so auch ein Inhaltsverzeichnis erstellen, das auf den Titeln basiert.
$html=file_get_contents('regex_tags.php'); // das zu analysierende File
preg_mach(), preg_match_all()
preg_mach() gibt sich mit der ersten Fundstelle zufrieden, preg_mach_all() fährt unmittelbar danach mit der Suche fort. Der erste Parameter ist das Suchmuster, der zweite ist der String in dem gesucht wird, der dritte speichert als Multi-Array den ganzen gefundenen String (Haupttreffern) und die einzelnen Gruppen (Nebentreffer), sofern welche durch Klammern im RegEx erstellt wurden, und zwar in der Reihenfolge, in der sie durch die FLAG festgelegt wurde (die FLAGs erkläre ich weiter unten).
Als Delimiter für den RegEx Anfang und Ende, verwende ich auf dieser Seite durchgehend das %-Zeichen, da der Slash ja schon in den Tags vorkommt ist das deutlicher zu lesen. Nach dem Delimiter, aber noch innerhalb der einfachen Anführungszeichen, habe ich oft ein i und ein U. Das sind Modifikatoren, i bedeutet die Gross-/Kleinschreibung zu missachten, U macht das Muster weniger 'greedy', das heisst weniger gierig und meint, es gibt sich mit dem nächten Fund zufrieden, auch wenn ein passenderer Treffer später folgt.
php Tag
FLAG PREG_PATTERN_ORDER
Dieses Muster findet <?php ?> mit Allem dazwischen.
Die FLAG PREG_PATTERN_ORDER
füllt den Arrayindex [0] mit allen Haupttreffern, den Index [1] mit den Nebentreffern
der ersten Gruppe und [2] mit den Nebentreffern der zweiten Gruppe, etc.
Iteriere ich mit einer Schleife durch den Array[0], so erhalte ich alle Haupttreffer.
$regex_php='%<.php\s([^>]+).>%';
if (preg_match_all($regex_php, $html, $my_phptags, PREG_PATTERN_ORDER)) {
foreach ($my_phptags[0] as $phps){
echo htmlentities($phps)."<br />";
}
}
<?php echo "$mein_title"; ?>
<?php echo "$mein_title"; ?>
h1 Tag
FLAG PREG_SET_ORDER
Die FLAG PREG_SET_ORDER füllt den Arrayindex [0] mit dem ersten Haupttreffern, dem ersten Nebentreffer,
und dem zweiten Nebentreffer eines Sets, etc. Der Index [1] wird mit dem zweiten Haupttreffer und seinen Nebentreffern als zweites Set gefüllt, etc.
Iteriere ich hier durch den Array[0], so erhalte ich den ersten Haupttreffer und seine Nebentreffer.
Ich gebe unten also nur einen h1-Titel aus, hätte es einen zweiten, dann würde der in der Ausgabe unbeachtet bleiben.
$regex_h1='%(<h1\b[^>]*>)(.*?)(</h1>)%iU';
if (preg_match_all($regex_h1, $html, $my_h1tags, PREG_SET_ORDER)) {
foreach ($my_h1tags[0] as $set){
echo htmlentities($set)."<br />";
}
}
<h1>
<?php echo "$mein_title"; ?>
</h1>
div oder p Tag
Alle weiteren Tags (mit schliessenden Tags) suche ich ganz ähnlich.
So gilt dieses Schema auch für Paragrafen, wenn div durch p ersetzt wird.
Das 'div' im schliessenden Tag wird hier aus dem Gruppen-Speicher geholt.
Die erste Buchstaben-Gruppe, erstellt durch das erste Klammerpaar (div) wird nach dem
Slash im Endtag durch \1 wiedergegeben.
Die zweite Gruppe umfasst die Attribute im Opentag. Die dritte Gruppierung,
der Text zwischen den Tags, wird als 3. Nebentreffer ausgegeben.
$regex_div='%<(div)([^>]*)>([^<]*)<\/\1>%iU';
if (preg_match_all($regex_div, $html, $my_divtags)) {
foreach ($my_divtags[3] as $divs){
echo htmlentities($divs)."<br />";
}
}
Container 2 mit class-Attribut.
img Tag
Der img Tag hat kein eindeutiges Endtag. Ohne FLAG-Angabe gilt by default PREG_PATTERN_ORDER.
$regex_img='%<\s*img[^>]+>%iU';
if (preg_match_all($regex_img, $html, $my_imgtags)) {
foreach ($my_imgtags[0] as $bild){
echo htmlentities($bild)."<br />";
}
}
Kommentar Tag
Der html Kommentar sucht seinesgleichen. Hier liesse sich der reine Kommentar (als Gruppe) verwerten.
$regex_comment='%<!--([^>]+)-->%iU';
if (preg_match_all($regex_comment, $html, $my_commenttags)) {
foreach ($my_commenttags[0] as $comment){
echo htmlentities($comment)."<br />";
}
}
br Tag
Der br Tag hat kein vom img Tag unterscheidbares Endtag, aber er hat möglichst wenig dazwischen.
$regex_br='%<br ( ?)(.?)\/>%iU';
if (preg_match_all($regex_br, $html, $my_brtags)) {
foreach ($my_brtags[0] as $brake){
echo htmlentities($brake)."|";
}
}
Alle Absätze einer Seite
Einer für alle Blockbilder
Dieses Suchmuster ist noch nicht ganz ausgereift, aber es würde alle Absätze einzeln auflisten, wenn es keine ineinander verschachtelten Tags und kein Kommentar-Tag hätte. Nun müsste ich das Muster mit if und oder ergänzen (was durchaus machbar wäre), zudem müsste ich wohl von Aussen nach Innen vorgehend (durch greedy Muster), die Ergebnisse immer wieder als Ausgangslage nutzend, die Verschachtelungen von html, head und body auflösen.
Vielleicht helfen auch diese leicht anderen regexp im Vergleich?
// $regexp='/(?s:.+<([A-Z][A-Z0-9]*)\b[^>]*>.*?<\/\1>)/iU'; // findet Tags mit selbem Endtag
// $regexp='/(?s:.+(<([\w]+)[^>]*>)(.*?)(<\/\\2>))/i'; // findet einen Umfassenden Tag (ist greedy)
// $regexp='/(?s:.+(.*[^>]+>|[^<\/.*>]))/iU'; // findet alle Anfangstags und Endtags einzeln
// $regexp='/(?s:.+<(.*)>(.*)<\/(.*)>)/iU'; // findet alle Tags (ausser ?php Tags)
$regex_blocks='%(?s:.+(<[^>]+>)(.*)([^>]+>))%iU';
if (preg_match_all($regex_blocks, $html, $my_blocks)) {
foreach($my_blocks[0] as $Absatz) {
// Anzeige der Tags mit Inhalten (alle Haupttreffer)
echo "<img src='../abc/images/abs_edit.gif' alt='Absatz' title='Absatz' />";
echo htmlentities($Absatz);
echo "<hr />";
}
# print_r ($my_tags[0]);
}
<?php // Variable
$mein_description='Variabler Seitenbeschrieb'; // für meta
$mein_keywords='Stichwort1, Stichwort2, Stichwort3'; // für meta
$mein_robots='index, follow'; // für meta
$mein_title='Mit RegEx HTML Tags analysieren'; // für title und h1-titel
?>
<html>
<head>
<title><?php echo "$mein_title"; ?></title>
</head>
<body>
<h1><?php echo "$mein_title"; ?></h1>
<h2>Kapitel</h2>
<h3>Untertitelchen</h3>
<p>Absatz 1 ohne Attribute, Zeilenumbrüche oder andere Tags</p>
<p class="box">
Absatz 2 mit class-Attribut
</p>
<div>
Container 1 ohne Attribute, Zeilenumbrüche oder andere Tags.
</div>
<p>
Absatz 3 mit 3 Zeilenumbrüchen
<br />
<br />
<br />
</p>
<!-- Ich bin ein Kommentar -->
<div class="box">
Container 2 mit class-Attribut.
</div>
<p>
Absatz 4 mit Bild <img src="images/face_2.jpg" alt="Bild" height="120px" width="120px" />
</p>
</body>
</html>Alle Tags einzeln
Eine alternative Vorgehensweise wäre, jedes Tag (ob öffnend oder schliessend) von < bis > vorerst einzeln auszugeben.
$regex_tags='%(.*[^>]+>|[^<\/.*>])%iU';
if (preg_match_all($regex_tags, $html, $my_tags)) {
foreach($my_tags[0] as $Tags) {
// Anzeige der einzelnen Tags und Inhalte
echo htmlentities($Tags);
echo "<br />";
}
}
<?php // Variable
$mein_description='Variabler Seitenbeschrieb'; // für meta
$mein_keywords='Stichwort1, Stichwort2, Stichwort3'; // für meta
$mein_robots='index, follow'; // für meta
$mein_title='Mit RegEx HTML Tags analysieren'; // für title und h1-titel
?><html>
<head>
<title>
<?php echo "$mein_title"; ?>
</title>
</head>
<body>
<h1>
<?php echo "$mein_title"; ?>
</h1>
<h2>
Kapitel</h2>
<h3>
Untertitelchen</h3>
<p>
Absatz 1 ohne Attribute, Zeilenumbrüche oder andere Tags</p>
<p class="box">
Absatz 2 mit class-Attribut </p>
<div>
Container 1 ohne Attribute, Zeilenumbrüche oder andere Tags. </div>
<p>
Absatz 3 mit 3 Zeilenumbrüchen <br />
<br />
<br />
</p>
<!-- Ich bin ein Kommentar -->
<div class="box">
Container 2 mit class-Attribut. </div>
<p>
Absatz 4 mit Bild <img src="images/face_2.jpg" alt="Bild" height="120px" width="120px" />
</p>
</body>
</html>