Regex wählt den gesamten Text zwischen den Tags aus

142

Was ist der beste Weg, um den gesamten Text zwischen zwei Tags auszuwählen - z. B. den Text zwischen allen "Pre" -Tags auf der Seite.

Basheps
quelle
2
Der beste Weg ist, einen HTML-Parser wie "Beautiful Soup" zu verwenden, wenn Sie in Python sind ...
Fredrik Pihl
1
Am besten verwenden Sie den XML / HTML-Parser.
Daniel O'Hara
4
Im Allgemeinen ist die Verwendung regulärer Ausdrücke zum Parsen von HTML keine gute Idee: stackoverflow.com/questions/1732348/…
murgatroid99
Analysieren Sie keinen Text zwischen Tags mit Regex, da willkürlich verschachtelte Tags HTML nicht regulär machen. Übereinstimmende Tags scheinen in Ordnung zu sein. /<div>.*?<\/div>/.exec("<div><div></div></div>")
JDH8

Antworten:

156

Sie können "<pre>(.*?)</pre>"pre verwenden (pre durch beliebigen Text ersetzen) und die erste Gruppe extrahieren (für spezifischere Anweisungen geben Sie eine Sprache an), dies setzt jedoch die vereinfachende Vorstellung voraus, dass Sie sehr einfaches und gültiges HTML haben.

Wie andere Kommentatoren vorgeschlagen haben, verwenden Sie einen HTML-Parser, wenn Sie etwas Komplexes tun.

PyKing
quelle
41
Dadurch wird nicht der Text zwischen den Tags ausgewählt, sondern die Tags.
Capikaw
3
Sie müssen die Auswahl mit ()
Sahu V Kumar
2
Für mehrzeilige Tags: <html_tag> (. +) ((\ S) + (. +)) + <\ / Html_tag>
Felipe Augusto
Dies ist immer noch sichtbar. Wenn Sie <pre>nach dem Versuch immer noch Tags sehen <pre>(.*?)<\/pre>, liegt dies daran, dass Sie sich ansehen, was von der vollständigen Übereinstimmung anstelle der (. *?) - Erfassungsgruppe erfasst wird. Klingt kitschig, aber ich denke immer "Klammer = Paar Diebe", denn wenn auf das nicht (ein ?wie in (?:oder folgt (?>, hat jedes Match zwei Captures: 1 für das vollständige Match und 1 für die Capture-Gruppe. Jeder zusätzliche Satz von Klammern fügt eine zusätzliche Erfassung hinzu. Sie müssen nur wissen, wie Sie beide Aufnahmen in der Sprache abrufen, mit der Sie arbeiten.
Rbsdca
137

Das Tag kann in einer anderen Zeile ausgefüllt werden. Deshalb \nmuss hinzugefügt werden.

<PRE>(.|\n)*?<\/PRE>
zac
quelle
5
Wichtiger Punkt zum Hinzufügen (.|\n)*?beim Umgang mit HTML-Tags über mehrere Zeilen hinweg. Die ausgewählte Antwort funktioniert nur, wenn sich die HTML-Tags in derselben Zeile befinden.
Caleuanhopkins
3
<PRE> (| \ n |. \ R \ n)? * <\ / PRE> für Windows - Zeilenenden
Mark
3
Niemals verwenden (.|\n)*?, um mit einem Zeichen übereinzustimmen. Immer .mit dem sModifikator (Singleline) verwenden. Oder eine [\s\S]*?Problemumgehung.
Wiktor Stribiżew
Ich wollte /\*(.|\n)*?\*/
Codekommentare
perfekte Antwort vielen Dank
Omda
25

Das würde ich verwenden.

(?<=(<pre>))(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|`~]| )+?(?=(</pre>))

Grundsätzlich ist es:

(?<=(<pre>))Die Auswahl muss mit einem <pre>Tag vorangestellt werden

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| )Dies ist nur ein regulärer Ausdruck, den ich anwenden möchte. In diesem Fall werden Buchstaben, Ziffern, Zeilenumbrüche oder Sonderzeichen ausgewählt, die im Beispiel in eckigen Klammern aufgeführt sind. Das Pipe-Zeichen |bedeutet einfach " ODER ".

+?Pluszeichenzustände zur Auswahl eines oder mehrerer der oben genannten - die Reihenfolge spielt keine Rolle. Das Fragezeichen ändert das Standardverhalten von "gierig" in "ungierig".

(?=(</pre>))Die Auswahl muss an das </pre>Tag angehängt werden

Geben Sie hier die Bildbeschreibung ein

Abhängig von Ihrem Anwendungsfall müssen Sie möglicherweise einige Modifikatoren wie ( i oder m ) hinzufügen.

  • i - Groß- und Kleinschreibung wird nicht berücksichtigt
  • m - mehrzeilige Suche

Hier habe ich diese Suche in Sublime Text durchgeführt, sodass ich in meinem regulären Ausdruck keine Modifikatoren verwenden musste.

Javascript unterstützt kein Lookbehind

Das obige Beispiel sollte mit Sprachen wie PHP, Perl, Java ... gut funktionieren. Javascript unterstützt jedoch kein Lookbehind, sodass wir die Verwendung vergessen (?<=(<pre>))und nach einer Problemumgehung suchen müssen. Vielleicht entfernen Sie einfach die ersten vier Zeichen aus unserem Ergebnis für jede Auswahl wie hier. Regex-Match-Text zwischen Tags

Schauen Sie sich auch die JAVASCRIPT REGEX-DOKUMENTATION für nicht erfassende Klammern an

DevWL
quelle
Beachten Sie, dass Sie die einfachen / doppelten Anführungszeichen mit `maskieren müssen, um den regulären Ausdruck in eine Zeichenfolge einzufügen.
David Zwart
18

Verwenden Sie das folgende Muster, um Inhalte zwischen Elementen abzurufen. Ersetzen Sie [tag]durch das eigentliche Element, aus dem Sie den Inhalt extrahieren möchten.

<[tag]>(.+?)</[tag]>

Manchmal haben Tags Attribute, wie z. B. anchorTags, hrefund verwenden dann das folgende Muster.

 <[tag][^>]*>(.+?)</[tag]>
Shravan Ramamurthy
quelle
Versuchen Sie das erste Beispiel als '<head> (. +?) </ Head>' und funktioniert wie erwartet. Aber ich habe keine Ergebnisse mit dem zweiten.
Alex Byrth
1
das funktioniert nicht <[tag]>wird passen <t>, <a>und<g>
Martin Schneider
2
@ MA-Maddin - Ich denke du hast den Replace [tag] with the actual element you wish to extract the content fromTeil verpasst .
LWC
2
Na ja. Diese []sollten ganz weggelassen werden. Das wäre klarer, aufgrund ihrer Bedeutung in RegEx und der Tatsache, dass die Leute zuerst den Code scannen und danach den Text lesen;)
Martin Schneider
14

So schließen Sie die abgrenzenden Tags aus:

(?<=<pre>)(.*?)(?=</pre>)

(?<=<pre>) sucht nach Text nach <pre>

(?=</pre>) sucht vorher nach Text </pre>

Die Ergebnisse werden innerhalb des preTags geschrieben

Jean-Simon Collard
quelle
Leute, die diesen Blick auf die Antwort von @krishna thakor werfen, können auch prüfen, ob der Inhalt eine neue Zeile zwischen den Tags enthält
KingKongCoder
Dies hat in meinem Fall geholfen (ich muss keine Zeilenumbrüche berücksichtigen). Vielen Dank.
Pking
6

Sie sollten nicht versuchen, HTML mit regulären Ausdrücken zu analysieren. Sehen Sie sich diese Frage an und wie sie sich herausstellte.

Im einfachsten Sinne ist HTML keine reguläre Sprache, daher können Sie es nicht vollständig mit regulären Ausdrücken analysieren.

Sie können jedoch Teilmengen von HTML analysieren, wenn keine ähnlichen Tags verschachtelt sind. Solange etwas dazwischen liegt und nicht das Tag selbst ist, funktioniert dies:

preg_match("/<([\w]+)[^>]*>(.*?)<\/\1>/", $subject, $matches);
$matches = array ( [0] => full matched string [1] => tag name [2] => tag content )

Eine bessere Idee ist es, einen Parser wie das native DOMDocument zu verwenden, um Ihr HTML zu laden, dann Ihr Tag auszuwählen und das innere HTML zu erhalten, das ungefähr so ​​aussehen könnte:

$obj = new DOMDocument();
$obj -> load($html);
$obj -> getElementByTagName('el');
$value = $obj -> nodeValue();

Und da dies ein richtiger Parser ist, kann er Verschachtelungs-Tags usw. verarbeiten.

sg3s
quelle
2
Ich möchte nur sagen, dass ich ein wenig beunruhigt bin, dass dies immer noch negative Stimmen sammelt, während es die einzige Antwort ist, die neben der Regex-Lösung eine richtige Lösung liefert, und ich habe auch eine ausführliche Warnung hinzugefügt, dass dies wahrscheinlich nicht der richtige Weg ist ... Bitte kommentieren Sie zumindest, was an meiner Antwort so falsch ist.
SG3s
1
Die Frage wurde nicht mit markiert php. Ich
bin
@trincot Das war vor mehr als 7 Jahren, also kann ich mich nicht erinnern. In jedem Fall ist dies ein Beispiel für die Lösung des Problems mit einem regulären Ausdruck und einem Parser. Die Regex ist gut und PHP ist genau das, was ich damals gut wusste.
SG3s
Ich verstehe, ich habe Ihren ersten Kommentar gesehen und dachte, dass dies einige der Abstimmungen erklären könnte.
Trincot
4

Versuche dies....

(?<=\<any_tag\>)(\s*.*\s*)(?=\<\/any_tag\>)
Heriberto Rivera
quelle
3
Beachten Sie, dass Look Behind in JavaScript nicht unterstützt wird.
Allicarn
Oooo natürlich, aber dieser reguläre Ausdruck ist für Java. Vielen Dank für Ihre Nachricht.
Heriberto Rivera
4

Dies scheint der einfachste reguläre Ausdruck von allem zu sein, was ich gefunden habe

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. Schließen Sie das Eröffnungs-Tag (?:<TAG>)von den Übereinstimmungen aus
  2. Fügen Sie Leerzeichen oder Nicht-Leerzeichen ([\s\S]*)in die Übereinstimmungen ein
  3. Schließen Sie (?:<\/TAG>)das schließende Tag von den Übereinstimmungen aus
maqduni
quelle
3

Diese Antwort setzt Unterstützung für das Umsehen voraus! Dadurch konnte ich den gesamten Text zwischen Paaren von öffnenden und schließenden Tags identifizieren. Das ist der ganze Text zwischen dem '>' und dem '<'. Es funktioniert, weil das Umsehen nicht die Zeichen verbraucht, mit denen es übereinstimmt.

(? <=>) ([\ w \ s] +) (? = </)

Ich habe es in https://regex101.com/ mit diesem HTML-Fragment getestet .

<table>
<tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td></tr>
<tr><td>Cell 4</td><td>Cell 5</td><td>Cell 6</td></tr>
</table>

Es ist ein Spiel aus drei Teilen: dem Blick nach hinten, dem Inhalt und dem Blick nach vorne.

(?<=>)    # look behind (but don't consume/capture) for a '>'
([\w\s]+) # capture/consume any combination of alpha/numeric/whitespace
(?=<\/)   # look ahead  (but don't consume/capture) for a '</'

Screenshot von regex101.com

Ich hoffe, das dient als Start für 10. Glück.

Clarius
quelle
Danke dir. Dies ist nicht nur eine bessere Antwort, sondern auch ein großartiger Link zur regex101-Site. Upvoted! 🙂
Sean Feldman
2

var str = "Lorem ipsum <pre>text 1</pre> Lorem ipsum <pre>text 2</pre>";
    str.replace(/<pre>(.*?)<\/pre>/g, function(match, g1) { console.log(g1); });

Da die akzeptierte Antwort ohne Javascript-Code ist, fügen Sie Folgendes hinzu:

Shishir Arora
quelle
1

preg_match_all(/<pre>([^>]*?)<\/pre>/,$content,$matches)Diese Regex wählt alles zwischen Tags aus. egal es ist in neuer Zeile (arbeiten mit mehrzeiligen.

Krishna Thakor
quelle
1

In Python DOTALLerfasst das Setzen des Flags alles, einschließlich Zeilenumbrüche.

Wenn das DOTALL-Flag angegeben wurde, entspricht dies jedem Zeichen, einschließlich einer neuen Zeile. docs.python.org

#example.py using Python 3.7.4  
import re

str="""Everything is awesome! <pre>Hello,
World!
    </pre>
"""

# Normally (.*) will not capture newlines, but here re.DOTATLL is set 
pattern = re.compile(r"<pre>(.*)</pre>",re.DOTALL)
matches = pattern.search(str)

print(matches.group(1))

python example.py

Hello,
World!

Erfassen von Text zwischen allen öffnenden und schließenden Tags in einem Dokument

Es finditerist nützlich , Text zwischen allen öffnenden und schließenden Tags in einem Dokument zu erfassen . Im folgenden Beispiel sind drei öffnende und schließende <pre>Tags in der Zeichenfolge vorhanden.

#example2.py using Python 3.7.4
import re

# str contains three <pre>...</pre> tags
str = """In two different ex-
periments, the authors had subjects chat and solve the <pre>Desert Survival Problem</pre> with a
humorous or non-humorous computer. In both experiments the computer made pre-
programmed comments, but in study 1 subjects were led to believe they were interact-
ing with another person. In the <pre>humor conditions</pre> subjects received a number of funny
comments, for instance: “The mirror is probably too small to be used as a signaling
device to alert rescue teams to your location. Rank it lower. (On the other hand, it
offers <pre>endless opportunity for self-reflection</pre>)”."""

# Normally (.*) will not capture newlines, but here re.DOTATLL is set
# The question mark in (.*?) indicates non greedy matching.
pattern = re.compile(r"<pre>(.*?)</pre>",re.DOTALL)

matches = pattern.finditer(str)


for i,match in enumerate(matches):
    print(f"tag {i}: ",match.group(1))

python example2.py

tag 0:  Desert Survival Problem
tag 1:  humor conditions
tag 2:  endless opportunity for self-reflection
John
quelle
0

Für mehrere Zeilen:

<htmltag>(.+)((\s)+(.+))+</htmltag>
Dilip
quelle
0

Sie können verwenden Pattern pattern = Pattern.compile( "[^<'tagname'/>]" );

Ambrish Rajput
quelle
0

Ich benutze diese Lösung:

preg_match_all( '/<((?!<)(.|\n))*?\>/si',  $content, $new);
var_dump($new);
T.Todua
quelle
-1

In Javascript (unter anderem) ist dies einfach. Es umfasst Attribute und mehrere Zeilen:

/<pre[^>]*>([\s\S]*?)<\/pre>/
Jonathan
quelle
-4
<pre>([\r\n\s]*(?!<\w+.*[\/]*>).*[\r\n\s]*|\s*[\r\n\s]*)<code\s+(?:class="(\w+|\w+\s*.+)")>(((?!<\/code>)[\s\S])*)<\/code>[\r\n\s]*((?!<\w+.*[\/]*>).*|\s*)[\r\n\s]*<\/pre>
user5988518
quelle
6
Bitte stellen Sie Ihre Antwort mit Worten vor / erklären Sie sie.
Andrew Regan