Regex zaznacz cały tekst między tagami

143

Jaki jest najlepszy sposób zaznaczenia całego tekstu między dwoma tagami - np. Tekst między wszystkimi tagami „przed” na stronie.

basheps
źródło
2
Najlepszym sposobem jest użycie parsera html, takiego jak „Beautiful Soup”, jeśli interesujesz się Pythonem ...
Fredrik Pihl
1
Najlepszym sposobem jest użycie parsera XML / HTML.
Daniel O'Hara
4
Ogólnie rzecz biorąc, używanie wyrażeń regularnych do analizowania html nie jest dobrym pomysłem: stackoverflow.com/questions/1732348/ ...
murgatroid99
Nie analizuj tekstu między tagami z wyrażeniem regularnym, ponieważ arbitralnie zagnieżdżone tagi powodują, że HTML nie jest regularny. Wydaje się, że dopasowanie tagów jest w porządku. /<div>.*?<\/div>/.exec("<div><div></div></div>")
jdh8

Odpowiedzi:

157

Możesz użyć "<pre>(.*?)</pre>", (zastępując pre dowolnym tekstem) i wyodrębnić pierwszą grupę (dla bardziej szczegółowych instrukcji określ język), ale zakłada to uproszczone założenie, że masz bardzo prosty i poprawny HTML.

Jak sugerowali inni komentatorzy, jeśli robisz coś złożonego, użyj parsera HTML.

PyKing
źródło
41
Nie powoduje to zaznaczenia tekstu między tagami, ale obejmuje tagi.
capikaw
3
Musisz pobrać zaznaczenie za pomocą ()
Sahu V Kumar
2
W przypadku tagów wieloliniowych: <html_tag> (. +) ((\ S) + (. +)) + <\ / Html_tag>
Felipe Augusto,
To nadal jest widoczne, więc: jeśli nadal widzisz <pre>tagi po próbie <pre>(.*?)<\/pre>, to dlatego, że patrzysz na to, co zostało przechwycone przez pełne dopasowanie, a nie przez grupę przechwytywania (. *?). Brzmi tandetnie, ale zawsze myślę, że „nawias = para złodziei”, ponieważ jeśli nie (nastąpi po nim ?jak w (?:lub (?>, każdy mecz będzie miał dwa przejęcia: 1 za cały mecz i 1 za grupę przechwytującą. Każdy dodatkowy zestaw nawiasów powoduje dodatkowe przechwycenie. Musisz tylko wiedzieć, jak pobrać oba przechwytywania w dowolnym języku, z którym pracujesz.
rbsdca
137

Tag można uzupełnić w innej linii. Dlatego \nnależy dodać.

<PRE>(.|\n)*?<\/PRE>
zac
źródło
5
Ważna uwaga dotycząca dodawania w (.|\n)*?przypadku tagów HTML w wielu wierszach. Wybrana odpowiedź działa tylko wtedy, gdy tagi HTML znajdują się w tej samej linii.
Caleuanhopkins
3
<PRE> (. | \ N | \ r \ n) *? <\ / PRE> dla zakończeń linii w systemie Windows
Mark
3
Nigdy nie używaj (.|\n)*?do dopasowania żadnego znaku. Zawsze używaj .z smodyfikatorem (singleline). Lub [\s\S]*?obejście.
Wiktor Stribiżew
Chciałem zaznaczyć komentarze do kodu w notatniku ++, więc korzystając z tej odpowiedzi wymyśliłem, /\*(.|\n)*?\*/który wykonał zadanie - dziękuję
wkille
doskonała odpowiedź, wielkie dzięki
Omda
25

To jest to, czego bym użył.

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

Zasadniczo to, co robi, to:

(?<=(<pre>))Wybór należy poprzedzić <pre>tagiem

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| )To jest tylko wyrażenie regularne, które chcę zastosować. W tym przypadku wybiera literę, cyfrę lub znak nowego wiersza lub niektóre znaki specjalne wymienione w przykładzie w nawiasach kwadratowych. Pionowa |kreska oznacza po prostu „ LUB ”.

+?Stany znaku plus, aby wybrać jeden lub więcej z powyższych - kolejność nie ma znaczenia. Znak zapytania zmienia domyślne zachowanie z „zachłannego” na „niezadowolony”.

(?=(</pre>))Wybór musi być dołączony do </pre>tagu

wprowadź opis obrazu tutaj

W zależności od przypadku użycia może być konieczne dodanie modyfikatorów, takich jak ( i lub m )

  • i - bez rozróżniania wielkości liter
  • m - wyszukiwanie wieloliniowe

Tutaj przeprowadziłem to wyszukiwanie w Sublime Text, więc nie musiałem używać modyfikatorów w moim wyrażeniu regularnym.

Javascript nie obsługuje lookbehind

Powyższy przykład powinien działać dobrze z takimi językami jak PHP, Perl, Java ... Javascript nie obsługuje jednak lookbehind, więc musimy zapomnieć o używaniu (?<=(<pre>))i poszukać jakiegoś obejścia. Być może po prostu usuń pierwsze cztery znaki z naszego wyniku dla każdego zaznaczenia, tak jak tutaj Regex dopasowuje tekst między tagami

Zobacz również w dokumentacji JavaScript REGEX dla non-przechwytywanie nawiasach

DevWL
źródło
Zauważ, że aby umieścić wyrażenie regularne w łańcuchu, musisz zmienić znaczenie znaków pojedynczych / podwójnych cudzysłowów za pomocą `.
David Zwart,
18

użyj poniższego wzorca, aby uzyskać zawartość między elementem. Zastąp [tag]rzeczywisty element, z którego chcesz wyodrębnić zawartość.

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

Czasami tagi będą miały atrybuty, takie jak anchorposiadanie tagu href, a następnie użyj poniższego wzorca.

 <[tag][^>]*>(.+?)</[tag]>
Shravan Ramamurthy
źródło
Wypróbuj pierwszy przykład jako „<head> (. +?) </head>” i działa zgodnie z oczekiwaniami. Ale nie mam wyników z drugim.
Alex Byrth
1
to nie działa. <[tag]>będzie pasował <t>, <a>i<g>
Martin Schneider
2
@ MA-Maddin - Myślę, że przegapiłeś Replace [tag] with the actual element you wish to extract the content fromczęść.
LWC
2
No cóż, tak. Te []należało całkowicie pominąć. Byłoby to bardziej jasne, ze względu na ich znaczenie w RegEx oraz fakt, że ludzie najpierw skanują kod, a potem czytają tekst;)
Martin Schneider
14

Aby wykluczyć znaczniki ograniczające:

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

(?<=<pre>) szuka tekstu po <pre>

(?=</pre>) szuka tekstu wcześniej </pre>

Wyniki będą zawierać tekst wewnątrz pretagu

Jean-Simon Collard
źródło
Osoby korzystające z tego spojrzenia na odpowiedź @krishna thakor, która może również rozważyć, czy treść ma nową linię między tagami
KingKongCoder
Pomogło to w moim przypadku (bez konieczności rozważania nowych linii). Dzięki.
Pking
6

Nie powinieneś próbować analizować html za pomocą wyrażeń regularnych, zobacz to pytanie i jak się okazało.

Mówiąc najprościej, html nie jest językiem zwykłym, więc nie można w pełni przeanalizować tego za pomocą wyrażeń regularnych.

Powiedziawszy, że możesz analizować podzbiory html, gdy nie ma zagnieżdżonych podobnych tagów. Tak więc, o ile wszystko pomiędzy i nie jest tym tagiem, zadziała:

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

Lepszym pomysłem jest użycie parsera, takiego jak natywny DOMDocument, do załadowania kodu HTML, a następnie wybranie tagu i uzyskanie wewnętrznego kodu HTML, który może wyglądać mniej więcej tak:

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

A ponieważ jest to właściwy parser, będzie w stanie obsłużyć tagi zagnieżdżania itp.

sg3s
źródło
2
Chcę tylko powiedzieć, że jestem trochę zaniepokojony, że nadal zbiera się głosy przeciwne, podczas gdy jest to jedyna odpowiedź, która dostarcza właściwe rozwiązanie obok wyrażenia regularnego, a także dodałem obszerne ostrzeżenie, że prawdopodobnie nie jest to właściwy sposób ... Proszę przynajmniej skomentować, co jest nie tak w mojej odpowiedzi.
sg3s
1
Pytanie nie zostało oznaczone tagiem php. Nie jestem pewien, jak pojawił się PHP ...
trincot
@trincot To było ponad 7 lat temu, więc nie pamiętam. W każdym razie jest to przykład rozwiązania problemu za pomocą wyrażenia regularnego i parsera. Wyrażenie regularne jest dobre, a php jest tym, co dobrze znałem w tamtym czasie.
sg3s
Rozumiem, widziałem twój pierwszy komentarz i pomyślałem, że może to wyjaśnić niektóre z negatywnych opinii.
trincot
5

Spróbuj tego....

(?<=\<any_tag\>)(\s*.*\s*)(?=\<\/any_tag\>)
Heriberto Rivera
źródło
3
Zwróć uwagę, że spoglądanie do tyłu nie jest obsługiwane w JavaScript.
allicarn
Ooo, oczywiście, ale to wyrażenie regularne dotyczy Javy. dziękuję za twoją notatkę.
Heriberto Rivera
4

Wydaje się, że jest to najprostsze wyrażenie regularne ze wszystkich, jakie znalazłem

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. Wyklucz otwierający tag (?:<TAG>)z dopasowań
  2. Uwzględnij ([\s\S]*)w dopasowaniach wszelkie znaki spacji lub inne niż białe znaki
  3. Wyklucz zamykający tag (?:<\/TAG>)z dopasowań
maqduni
źródło
3

Ta odpowiedź zakłada wsparcie dla rozglądania się! Pozwoliło mi to zidentyfikować cały tekst między parami znaczników otwierających i zamykających. To cały tekst między znakami „>” i „<”. Działa, ponieważ rozglądanie się nie zużywa dopasowanych znaków.

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

Przetestowałem to na https://regex101.com/ używając tego fragmentu HTML.

<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>

To gra składająca się z trzech części: spojrzenia za siebie, treści i spojrzenia w przyszłość.

(?<=>)    # 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 '</'

zrzut ekranu z regex101.com

Mam nadzieję, że będzie to początek dla 10. Szczęścia.

Clarius
źródło
Dziękuję Ci. To nie tylko lepsza odpowiedź, ale także świetny link do witryny regex101. Głosowano! 🙂
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); });

Ponieważ zaakceptowana odpowiedź jest bez kodu javascript, więc dodaj, że:

Shishir Arora
źródło
1

preg_match_all(/<pre>([^>]*?)<\/pre>/,$content,$matches)to wyrażenie regularne wybierze wszystko między tagami. nieważne, czy jest w nowej linii (praca z multiline.

Krishna thakor
źródło
1

W Pythonie ustawienie DOTALLflagi przechwyci wszystko, w tym znaki nowej linii.

Jeśli określono flagę DOTALL, pasuje ona do dowolnego znaku, w tym do nowej linii. 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!

Przechwytywanie tekstu między wszystkimi otwierającymi i zamykającymi tagami w dokumencie

finditerPrzydatne jest przechwytywanie tekstu między wszystkimi otwierającymi i zamykającymi znacznikami w dokumencie . W poniższym przykładzie w ciągu występują trzy <pre>znaczniki otwierające i zamykające .

#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
Jan
źródło
0

W przypadku wielu linii:

<htmltag>(.+)((\s)+(.+))+</htmltag>
Dilip
źródło
0

Możesz użyć Pattern pattern = Pattern.compile( "[^<'tagname'/>]" );

Ambrish Rajput
źródło
0

Używam tego rozwiązania:

preg_match_all( '/<((?!<)(.|\n))*?\>/si',  $content, $new);
var_dump($new);
T.Todua
źródło
-1

W Javascript (między innymi) jest to proste. Obejmuje atrybuty i wiele linii:

/<pre[^>]*>([\s\S]*?)<\/pre>/
Jonathan
źródło
-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
źródło
6
Wprowadź / wyjaśnij swoją odpowiedź słowami.
Andrew Regan