2009-07-13 7 views
45

Szukam wyrażenia regularnego pasującego do każdego nowego znaku linii (\n) wewnątrz znacznika XML, który jest <content> lub wewnątrz dowolnego znacznika, który jest wewnątrz tego <content> tag, na przykład:Wyrażenie regularne pasujące do każdego nowego znaku linii ( n) wewnątrz znacznika <content>

<blog> 
<text> 
(Do NOT match new lines here) 
</text> 
<content> 
(DO match new lines here) 
<p> 
(Do match new lines here) 
</p> 
</content> 
(Do NOT match new lines here) 
<content> 
(DO match new lines here) 
</content> 
+2

Czy to musi być wyrażenie regularne? –

+0

Czy chcesz dopasować tylko nowe linie lub cały tekst zgodnie z odpowiedzią Quartz? –

+0

Tak, powinno to być wyrażenie regularne i powinno pasować tylko do nowych linii. –

Odpowiedz

66

Właściwie ... nie można używać prostych regex tutaj, przynajmniej nie jeden. Prawdopodobnie musisz się martwić o komentarze! Ktoś może napisać:

<!-- <content> blah </content> --> 

Można przyjąć dwa podejścia tutaj:

  1. Strip wszystkie komentarze w pierwszej kolejności. Następnie użyj podejścia regex.
  2. Nie używaj wyrażeń regularnych i stosuj kontekstowe podejście do analizowania, które umożliwia śledzenie, czy zagnieżdżono się w komentarzu.

Bądź ostrożny.

Nie jestem również pewien, czy możesz dopasować wszystkie nowe linie naraz. @Quartz sugeruje to jedno:

<content>([^\n]*\n+)+</content> 

ten będzie pasował do żadnych znaczników treści, które mają znak nowej linii tuż przed tagiem zamykającym ... ale nie jestem pewien co masz na myśli poprzez dopasowanie wszystkie nowe linie. Czy chcesz mieć dostęp do wszystkich dopasowanych znaków nowej linii? Jeśli tak, najlepiej jest pobrać wszystkie tagi treści, a następnie wyszukać wszystkie znaki nowej linii, które są zagnieżdżone. Coś więcej tak:

<content>.*</content> 

ale jest jedno zastrzeżenie: Wyrażenia regularne są chciwi, więc to wyrażenie regularne dopasuje pierwszy znacznik otwierający do ostatniego zamknięcia jednego. Zamiast tego MUSISZ tłumić wyrażenie regularne, aby nie było chciwe. W językach takich jak Python, możesz to zrobić za pomocą "?" symbol regex.

Mam nadzieję, że dzięki temu możesz zobaczyć niektóre z pułapek i dowiedzieć się, jak chcesz postępować. Prawdopodobnie lepiej jest użyć biblioteki parsowania XML, a następnie iterować wszystkie tagi treści.

wiem, że nie może być oferując najlepsze rozwiązanie, ale przynajmniej mam nadzieję, że pojawi się w tym trudności i dlaczego inne odpowiedzi nie może być prawda ...

UPDATE 1:

Pozwolę sobie podsumować nieco więcej i dodać trochę więcej szczegółów do mojej odpowiedzi. Mam zamiar użyć składni regex Pythona, ponieważ jest to do czego jestem bardziej przyzwyczajony (wybacz mi z wyprzedzeniem ... być może trzeba będzie uciec z niektórych postaci ... komentarz do mojego posta i poprawię go):

Aby usunąć komentarze, użyj tego wyrażenia: Zwróć uwagę na "?" tłumi. *, aby nie był chciwy.

Podobnie, aby wyszukać tagi treści, należy użyć: . *?

Ponadto, może być w stanie to wypróbować, a dostęp do każdego znaku nowej linii z obiektami mecz grupy():

<content>(.*?(\n))+.*?</content> 

wiem, że mój wyciek jest wyłączony, ale oddaje ideę. Ten ostatni przykład prawdopodobnie nie zadziała, ale myślę, że najlepiej jest wyrazić to, co chcesz. Moja sugestia pozostaje: albo pobierz wszystkie tagi treści i zrób to sam, albo użyj biblioteki parsowania.

UPDATE 2:

Więc tutaj jest kod Pythona, który powinien działać. Nadal nie jestem pewien, co masz na myśli mówiąc "znajdź" wszystkie nowe znaki. Czy chcesz całe linie? Lub po prostu policzyć ile nowych linii. Aby uzyskać rzeczywiste linie, spróbuj:

#!/usr/bin/python 

import re 

def FindContentNewlines(xml_text): 
    # May want to compile these regexes elsewhere, but I do it here for brevity 
    comments = re.compile(r"<!--.*?-->", re.DOTALL) 
    content = re.compile(r"<content>(.*?)</content>", re.DOTALL) 
    newlines = re.compile(r"^(.*?)$", re.MULTILINE|re.DOTALL) 

    # strip comments: this actually may not be reliable for "nested comments" 
    # How does xml handle <!-- <!-- --> -->. I am not sure. But that COULD 
    # be trouble. 
    xml_text = re.sub(comments, "", xml_text) 

    result = [] 
    all_contents = re.findall(content, xml_text) 
    for c in all_contents: 
     result.extend(re.findall(newlines, c)) 

    return result 

if __name__ == "__main__": 
    example = """ 

<!-- This stuff 
ought to be omitted 
<content> 
    omitted 
</content> 
--> 

This stuff is good 
<content> 
<p> 
    haha! 
</p> 
</content> 

This is not found 
""" 
    print FindContentNewlines(example) 

Ten program drukuje wynik:

['', '<p>', ' haha!', '</p>', ''] 

pierwszy i ostatni pustych strunach pochodzą z nowej linii znaków bezpośrednio poprzedzającego pierwszy <p> i jeden pochodzących bezpośrednio po </p>. W sumie to (w przeważającej części) działa. Eksperymentuj z tym kodem i udoskonal go w zależności od potrzeb. Wydrukuj rzeczy w środku, aby zobaczyć, które wyrażenia pasują i nie pasują do siebie.

Mam nadzieję, że to pomoże :-).

PS - Nie miałem zbyt wiele czasu na wypróbowanie mojego wyrażeń z mojej pierwszej aktualizacji, aby uchwycić wszystkie nowe znaki ... daj mi znać, jeśli to zrobisz.

+0

Tutaj są dokumenty regex, na które patrzyłem dla pythona, kiedy napisałem powyższy kod (powinien być pomocny, jeśli nie znasz wyrażeń regularnych w pythonie): http://docs.python.org/library/re.html – Tom

+2

@Moayad: btw, ta metoda na pewno nie zadziała, jeśli istnieją zagnieżdżone znaczniki ... i żaden regex nie będzie w stanie jej obsłużyć. Regeksy naprawdę NIE nadają się do tego problemu. – Tom

+0

Wielkie dzięki za szczegółowe wyjaśnienie :) Z pewnością pomoże mi to zdecydować, co zrobić z tym problemem. Jeszcze raz dziękuję! –

4
<content>(?:[^\n]*(\n+))+</content> 
+1

Co zrobić, aby kwantyfikatory nie były chciwe? ([^ \ n] *? \ N +?) +?

+0

@Codebender, twój kod pasuje do wszystkiego wewnątrz tagu < content>, chcę dopasować tylko nowe linie. –

+0

Quarz, dziękuję, ale to nie jest to, czego szukam, twoje RegEx pasuje do każdego znaku między pierwszym znacznikiem otwierającym < content> i ostatnim znacznikiem zamykającym < /content>. Zaktualizowałem ten przykład, aby było nieco jaśniejsze. –

Powiązane problemy