Wyrażenie regularne

0

Witam, od jakiegoś czasu zmagam się z małym problemem.
Ogólnie moim zadaniem jest konwersja formatu html do fo (apache fop)
Problem pojawia się w chwili pozbycia się znaczników nierozpoznanych przez algorytm.
Poniżej przykład:

<b>tekst</b>
<fo:inline font-family="Helvetica">tekst... tekst...</fo:inline>

W przykładzie chcę pozbyć się wszystkich nie rozpoznanych znaczników, do tego celu używam wyrażenia regularnego, a właściwie AŻ! dwóch... :) ...

<[(/?fo:)].?>
i
</[
(fo:)].?>

Chciałbym zapiąć całość w jedno wyrażenie no ale niestety pierwsze wyrażenie łapie tylko nie fopowe znaczniki rozpoczynające, a drugie tylko zamykające. Z tego co rozumiem to wyszukuje wyrażeń które: zaczynają się od "<" następnie
mają lub też nie znak "/", dalej nie może być "fo:", następnie dowolny ciąg znaków i znacznik zamknięcia ">". Jeżeli to co napisałem było by prawdą to niezidentyfikowane znaczniki zamknięcia też powinny się w to łapać, ale niestety tak nie jest :/

Dodam, że wyrażenie można testować pod adresem: http://www.regexplanet.com/simple/index.html

Proszę o pomoc....

0

<[^(/?fo:)].*?> oznacza:

  • jeden znak <
  • jeden znak nie będący (, ), ?, f, o, :, /
  • najkrótszy dowolny ciąg kończący się znakiem >
    wyrażenie nie złapie ani </fo:whatever>, ani </font>, ani nawet dowolnego tagu zamykającego (bo będzie tam obecny /).

zapoznaj się z negative/positive lookahead/lookbehind

0

Z tego co przeczytałem to znaki "(" i ")" są znakami początku i końca łańcucha znaków?,
dalej znak ? jest znakiem specjalnym mówiącym o tym, że ciąg znaków lub znak przed nim w tym przypadku "/" może wystąpić raz lub wcale.
Czy mógłbyś napisać jak według Ciebie powinno wyglądać to wyrażenie?

0

nie ma w regexp czegoś takiego jak znaki oznaczające początek i koniec łańcucha znaków wewnątrz wyrażenia (nie mam na myśli $ ani ^). nawiasy służą
a) do grupowania reguł, dzięki czemu można łatwo robić alternatywy, np. (f|b)o(nt|ld) złapie font, bold, bont, fold;
b) do tworzenia grup, przez co możesz używać złapanego fragmentu tekstu jako replacementu, np. d(.)pa "zwróci" literę w nawiasie jako $1, wtedy preg_replace("dUpa", "d(.)pa", "$1") zwróci "U".

w Twoim wyrażeniu nadrzędne są nawiasy kwadratowe, oznaczające dowolny znak z lub spoza (^) podanych, i żaden nawias okrągły zawarty we wnętrzu nawiasów kwadratowych nie zmieni ich działania. innymi słowy [cokolwiek tu nie podasz będzie potraktowane jako zbiór znaków i nic innego], a [*] oznacza nie znicz, nie dowolny zestaw znaków i nie dowolną ilość znaków [, tylko jeden znak *.

opis lookahead/lookbehind znajdziesz tutaj: http://www.regular-expressions.info/lookaround.html. te wyrażenia nie są banalne, a ja siedzę w pracy i nie mam czasu sprawdzać, czy dobrze wymyśliłem regexa. poeksperymentuj sam, na przyszłość będziesz mieć wędkę zamiast ryby.

1

Nie jestem pewien czy lookahead / lookbehind tutaj pomoga, ja bym to zrobil pewnie tak:

String s = "<b>tekst</b><fo:inline font-family='Helvetica'>tekst... tekst...</fo:inline><i>kursywa</i>";
Pattern p = Pattern.compile("<(.*?)>.*?</\\1>");
Matcher m = p.matcher(s);
while (m.find()) {
    if (!m.group(1).startsWith("fo:")) {
        System.out.println(m.group());
    }
}

Opis: lapiemy caly znacznik w grupe 1, nastepnie ilestam znakow w srodku, i nastepnie zamykajacy znacznik ktorego testem musi byc to samo co wczesniej zlapalismy do grupy 1. Nastepnie, iterujemy sobie przez to co Matcher zlapal, i jesli nie zaczyna sie na 'fo:', jakos obrabiamy.

W sumie to chyba to dziala:

String s = "<b>tekst</b><fo:inline font-family='Helvetica'>tekst... tekst...</fo:inline><i>kursywa</i>";
Pattern p = Pattern.compile("<(?!fo:)(.*?)>.*?</(?!fo:)\\1>");
Matcher m = p.matcher(s);
while (m.find()) {
    System.out.println(m.group());
}

Czyli lookahead jednak daje rade.

0

Niestety nic z tego :)

</?[f][o][^:].?> - próbowałem tego, ale łapią się znaczniki końca fop...
Nie wiem czy dobrze rozumiem, ale na początek znak "<" 0 lub 1 / i dalej już nie w grupie negacja wystąpienia 3 znaków jeden po drugim: nie "f", nie "o" i nie ":".
Dodam, że wyrażenie </?fo:.
?> łapie wszystkie fopowe znaczniki więc wystarczy dobrze je zanegować i problem rozwiązany... tylko jak to zrobić nie tworząc grup, jeśli negowanie ^ ma wystąpić w nawiasie kwadratowym...

0

Ty, nie wiem czy zrozumialem co chesz zrobic, ale w pierwszym poscie masz napisane ze chcesz jedno wyrazenie ktore lapie nie-fopowe znaczniki. Powyzej Twojego ostatniego posta masz 2 kawalki kodu ktore robia to co chesz. OCB?

0

Wporządku masz rację sprawdziłem, na emulatorze wyrażeń regularnych online i nie działało...
sprawdziłem w NetBeans i działa :)

ale musisz mieć świadomość, że mogą być znaczniki które nie posiadają zakończenia... przykład poniżej:

"tekst <img src="aaa.jpg"/><fo:inline font-family='Helvetica'>tekst... tekst...</fo:inline>kursywa"

Ale to już rozwiązuje mój problem:

"<((?!fo:)(.*?)>.*?</(?!fo:)\\1)|<(?!/)[^f][^o][^:](.*?)>"

Teraz tylko pomierzyć czasu czy według przypuszczeń jedno wyrażenie bardziej złożone będzie szybsze od 2 prostszych.

I wyszło to czego się obawiałem... przy zapytaniu powyżej w przeciągu pięciu minut nie doczekałem się obliczenia dla 2000 linii z znacznikami html, natomiast dla wyrażenia "<(?!fo:)(.*?)>.*?</(?!fo:)\\1" wynik to około 6/7 sekund, ale pozostaje konieczność dodania drugiego wyrażenia dla znaczników bez zakończenia...

Udało się :D oto zwycięzca konkursu wyrażeń... <(?!(fo:)|(/fo:))(.*?)>

Dziękuję za pomoc

1 użytkowników online, w tym zalogowanych: 0, gości: 1