2012-12-12 15 views
5

* Uwaga: Wyjście z Array() jest print_r PHP() *Regex aby zatrzymać w pierwszym wystąpieniu # łańcucha # wewnątrz regex

mam ten tag HTML:

<tr> 
    <td width="40" align="left"><div class="icSkill" id="skill4"></div></td> 
    <td colspan="2">SOME_VALUE_I_WANT&nbsp;</td> 
</tr> 

Naprawdę chcę wyodrębnić to z RegEx i nie chcę używać parserów HTML w tym przypadku.

zrobić to Regex (używam S-flagę zignorować znaki nowej linii pliku);:

\<tr\>\<td\swidth="40"\salign="left"\>\<div\s+class="icSkill"\s+id="skill(\d+)".*\<\/tr\> 

Problem jest teraz, że regex nie zatrzymuje się na pierwszym Close znacznik TR, ale chcę to do. Wiem, że prawdopodobnie ma coś todo z twierdzeniami, tylko ja nie wiem jak.

Array 
(
    [0] => <tr><td width="40" align="left"><div class="icSkill" id="skill4"></div></td><td colspan="2">SOME_VALUE_I_WANT&nbsp; 
</td></tr><tr><td rowspan="2" align="left"><div class="icGuard" id="guard9"></div></td></tr> 
    [1] => 4 
) 

Podstawowe przykłady, takie jak:/[^ <] */nie będą działać w tym przypadku. Jest tam również sposób regex powiedzieć coś takiego:

/[^A_STRING]*/ (in words; stop unless you find A_STRING) 
OR BETTER EXAMPLE: 
/[^A_STRING_FIRST_TIME]*/ (in words; stop unless you find A_STRING for the FIRST_TIME) 
+1

Dlaczego nie chcesz używać analizatora HTML w tym przypadku? –

+0

Gdzie jest twój kod? Nie widać modyfikatorów, których używasz. Najprawdopodobniej brakuje ci modyfikatora "U". Poza tym, spraw, żebyś chciał używać parserów html (aka domdocument) – Alex

+0

Może powinienem był zadać to pytanie inaczej, przepraszam. Chcę tylko wiedzieć, czy mogę zrobić \ [^ a] \ gdzie "a" byłoby ciągiem znaków. Nie chcę tego \ [^ abc] \, ponieważ pozwala to wszystkim na ważne wyjątki. –

Odpowiedz

9

Problem polega greediness. .* zużywa tyle, ile może. Można zrobić to ungreedy dołączając ?:

~<tr><td\s+width="40"\s+align="left"><div\s+class="icSkill"\s+id="skill(\d+)".*?</tr>~s 

Także, jak widać, naprawdę nie ma potrzeby, aby zrobić tak wiele ucieczki. To tylko utrudnia czytelność.

Alternatywnym sposobem powtarzania powtarzania jest użycie modyfikatora U, który powoduje, że wszystkie powtórzenia są globalnie niekompletne w całym wzorze. Preferuję lokalny wariant (używając ?).

W każdym razie, istnieje inna możliwość, która naśladuje [^A_STRING]* (co nie działa, ponieważ pasuje dowolny ciąg znaków, które nie zawierają A, _, S, T, R, I, N lub G). Można użyć negative lookahead na każdym stanowisku powtórzenia:

(?:(?!A_STRING).)* 

(zastępcze to dla .* lub .*?). W większości przypadków powinien być równoważny, ale czas wykonania może się różnić. Co więcej, trochę trudniej to rozszyfrować.

+0

Dzięki, naprawdę świetnie! Chciałem przede wszystkim poznać "struny" - również w przyszłości. Dotyczące przesadnego ucieczki; Staram się trzymać niedozwolonych postaci na arkuszu, którego używam na stronie AddedBytes.com. Podaje metaznaki, które muszą być zmienione:^[. $ {* (\ +) |? <> Jednak czasami wydaje się, że PHP dusi się, jeśli nie uniknę ukośnika (/). Po raz kolejny moje podziękowania ^^ –

+0

@Allendar '/' musi być tylko zmienione, jeśli użyjesz '/' jako ogranicznika. Dlatego nigdy nie uciekaj '/'. Zamiast tego poszukaj znaku ogranicznika, który nie jest częścią twojego regex. Dla innych. Zgadzam się z tymi wszystkimi, ale '<>' są tylko meta-znakami, jeśli są używane jak '(? ...' lub '(? P ...'. Tak więc zazwyczaj możesz zostawić je bez zmiany znaczenia. Wyrażenia są zazwyczaj trudne do odczytania, więc chciałbym zmniejszyć bałagan, uciekając jak najwięcej. (Również w klasach postaci, musisz tylko uciec '^', ']', '\' i '-' - po prostu FYI) –

+0

Dzięki M, to bardzo mi pomaga. W przeszłości robiłem Regexa, ale za każdym razem, gdy go odbieram, czuję, że muszę go na nowo nauczyć, haha, –

1

To jest trudne. Zwykle masz tam identyfikator klasy, co ułatwiłoby ci to.

Upewnijmy się więc, że rozumiem, co chcesz: Musisz uchwycić wszystko, co znajduje się w ostatnim tagu <td>, tuż przed zamknięciem wiersza tabeli. W takim przypadku trzeba negatywny uprzedzona:

<td(?!.*?<td).*?>(.*?)<\/td>

To, wraz z modyfikatora s, pobudzi SOME_VALUE_I_WANT&nbsp;, pod warunkiem, że jest w ostatnim <td> elementu w wierszu tabeli.

Jedynym elementem tego prostego wyrażenia, który nie jest prosty, jest operator negatywnej operacji wyprzedzającej <td(?!.*?<td), który przechwyci jedynie element <td>, po którym nie następuje inny taki element.

Ponadto, gdy używasz operatora gwiazdy, zazwyczaj chcesz się upewnić, że nie zmienisz go tak, by był nieagrypcyjny: (.*?). Oznacza to, że zatrzymuje się w pierwszym meczu.

+0

Dzięki za dogłębny opis Nitay. To sprawia, że ​​rzeczy bardzo jasne ^^ –

+0

Czy to nie dostanie ostatniego "" na wejściu, bez względu na to, '' '' 'jest w? –

+0

@ m.buettner Tak. Z OP nie wynika dokładnie, jakie są dokładne cechy wzoru, który stara się dopasować. Tak to rozumiałem. W każdym razie, parsowanie HTML z wyrażeń regularnych nie jest prawdopodobnie czymś, co powinniśmy robić bardzo często, są one zbyt rozwlekłe w tym celu. – NitayArt

Powiązane problemy