Edytor znaczników formatu tekstu - problem z Regex

Edytor znaczników formatu tekstu - problem z Regex
CL
  • Rejestracja:prawie 16 lat
  • Ostatnio:8 miesięcy
0

Chciałbym dostosować do swoich potrzeb lub stworzyć edytor znaczników formatu tekstu tak jak jest to możliwe dla komponentu FormatedLabel od DevExpress:
screenshot-20210521200214.png
screenshot-20210521200231.png
Problem polega na tym, że moje znaczniki nie są BBCode tylko używają nawiasów ostrych < > zamiast kwadratowych jak w przykładzie i trochę inaczej zapisują kolor czcionki.
Swoich znaczników nie zmienię, ponieważ pochodzą z gotowego rozwiązania.
Na początku zacząłem przerabiać edytor od DevExpress i było całkiem nieźle do momentu konwertowania pomiędzy widokami. Ingerowanie w ich kod głębiej nie ma sensu bo to multum roboty ale w ostateczności może jeszcze raz do tego usiądę.
Potrzebne mi są jedynie 4 znaczniki: pogrubienie, kursywa, podkreślenie i kolor czcionki. Chciałem stworzyć swój edytor na wzór tego powyższego ale mam problem ze znalezieniem fragmentów tekstu ze znacznikami, który mam formatować. Chciałem ugryźć to regexami ale nie pracuje z nimi na co dzień więc mam problem.
Załóżmy, że mam taki tekst ze znacznikami:

Kopiuj
początek <b> pogrubienie1 </b> =  <b> pobrubienie2 </b> coś na końcu

Potrzebuję wyciągnąć teraz z tego pary znaczników

Kopiuj
<b> </b>

żeby odpowiednio pogrubić widok w RTF.
Napisałem takie wyrażenie:

Kopiuj
([^<>]*)(<b>)([^<>]*)(</b>)([^<>]*)

które teoretycznie dla danego przykładu działa ok ale przy zagnieżdżonych innych znacznikach będzie problem. Mam 2 dopasowania i mogę wyciągnąć wszystko i zmienić to co mi jest potrzebne.
Problem w tym, że przy błędach w tekście wyrażenie pomija część tekstu, czyli przy konwertowaniu ucięło by mi informacje. Przykład błędnego tekstu, który nie zostanie prawidłowo rozpoznany przez moje wyrażenie:

Kopiuj
początek nie jest łapany <b> pierwszy znacznik bez domknięcia <b> pogrubienie1 </b> =  <b> pobrubienie2 </b> coś na końcu

Przy dodatkowych znacznikach jest podobnie:

Kopiuj
<b> <i>pogrubienie i kursywa nie łapane</i> </b> =  <b> pobrubienie2 </b> coś na końcu

Zmodyfikowałem wyrażenie na takie:

Kopiuj
([^<>]*)(<b>|<i>)([^<>]*)(</b>|</i>)([^<>]*)

ale dalej w pierwszej części nie łapie mi pogrubienia, tylko kursywę.
Z tym też jest problem na początku:

Kopiuj
<b> prawa < lewa </b> =  <b> pobrubienie2 </b> coś na końcu

Wyrażenia testuję na https://regex101.com/
Czy ktoś byłby w stanie mi pomóc z tymi regexami?
Alternatywnie może można to zrobić inaczej?

szatkus
Nie czytałeś tego klasyka o regexach i htmlu? https://stackoverflow.com/a/1732454/10941102
CL
Nie pracuje w webie, nie czytałem tego wcześniej ale coś w tym jest.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 11 godzin
  • Lokalizacja:Tuchów
  • Postów:12172
2

Kiedyś stworzyłem sobie formatowalną etykietę, która wspierała znaczniki HTML — podział tekstu na nagłówki i paragrafy, wsparcie tekstu zwykłego, pogrubionego, pochylonego i przekreślonego, a także obsługa klikalnych linków (jedno- lub wielowierszowych). Co prawda zestaw znaczników i funkcji nieco inny niż Twój, ale podobieństwo dość wyraźne.

Aby przerobić goły tekst na informacje wymagane do wyrenderowania etykiety, treść traktowałem jako jeden ciąg znaków i analizowałem go znak po znaku, wyrzucając do listy kolejne tokeny (słowo lub znacznik). Kolejnym krokiem było obliczenie pozycji każdego słowa na ekranie, zgodnie z kolejnością tokenów w liście. Na koniec wyznaczało się obszary linków, czyli miejsca, w których kursor miał się na łapkę zmienić. Ostatni krok to renderowanie, czyli iteracja po liście tokenów z kompletnymi danymi — jeśli tokenem było słowo, to renderowało się tekst, a jeśli znacznik, to zmieniało styl fontu itp.

Tak więc sugeruję wywalić wyrażenia regularne i parsować tekst w ww. sposób. Znak po znaku, wyciągać tokeny i wrzucać na listę. Czyli zrobić sobie po prostu zwyczajny parser i podejść do formatowalnego tekstu jak do kodu źródłowego.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
CL
  • Rejestracja:prawie 16 lat
  • Ostatnio:8 miesięcy
0

Liczyłem, że da radę zrobić to "wygodniej". Spróbuję chyba najpierw pogrzebać w kodzie DevExpress bo mimo wszystko wydaje mi się, że będzie z tym mniej pracy niż pisać wszystko od początku. Jeśli jednak nie uda się tamtego przerobić to chyba Twoja propozycja będzie jedynym wyjściem.

Freja Draco
Freja Draco
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:3394
1

Sugeruję użyć takich wzorców:
(<b>)(.*?)(<\/b>)
(<i>)(.*?)(<\/i>)
(<u>)(.*?)(<\/u>)
I potraktować po kolei osobno dla każdego znacznika do podmiany.


CL
  • Rejestracja:prawie 16 lat
  • Ostatnio:8 miesięcy
0

Wiedziałem, że przekombinowałem. Wzorce @Freja Draco rozwiązują mój problem z Regexem. Dzięki!
W między czasie udało mi się prawie przerobić kod, który obstawiałem, że będzie sprawiał problemy. Potestuję i wybiorę ostateczne rozwiązanie do mojego problemu.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 11 godzin
  • Lokalizacja:Tuchów
  • Postów:12172
2

Nie no spoko, tylko ciekaw jestem co zrobisz, jak zechcesz dodać obsługę innych znaczników. Będziesz wydłużał regexy w nieskończoność? Przyjdzie czas, że dojdą kolejne znaczniki i Twoje rozwiązanie zacznie Ci mocno ciążyć. A parsowanie tekstu i rozkładanie go na tokeny to raptem dwie pętle i opcjonalne kopiowanie fragmentów tekstu. :D

Nie chcę Cię zmuszać do niczego, ale pamiętaj, że regexy to nie jest jedyne rozwiązanie. Przy czym jeśli zależy Ci jedynie na zamianie jednych znaczników na inne (nie bawiłem się RichEditami i nie wiem, jakich znaczników używają), to spokojnie możesz użyć funkcji StringReplace z flagą rfReplaceAll.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 4x, ostatnio: flowCRANE
pstmax
Dla nauki programowania wspaniały przykład. Jeżeli ma to być użytkowane --> Po rostu użyj darmowego Notepad++ tam to wszystko masz i działa rewelacyjnie.
CL
  • Rejestracja:prawie 16 lat
  • Ostatnio:8 miesięcy
0

Nowych znaczników nie będzie bo to adaptacja do rozwiązania zewnętrznego, które nie przewiduje dalszego rozwoju w tym kierunku. A jeśli coś by się miało w tym zmienić to nie w ciągu najbliższych kilku lat.
Z RichEditem nie chodzi o znaczniki bo tam formatowanie jest za pomocą stylowania:

Kopiuj
Rtf.SelAttributes2.Style := Rtf.SelAttributes2.Style + [fsBold]

Ale żeby to zmienić to muszę wydobyć tekst ze znaczników, znaczniki wywalić i sformatować wnętrze.
Tak jak podawałem przykłady powyżej StringReplace w tym przypadku nie byłoby dobrym rozwiązaniem (zakładając że chodziło by tylko o podmianę tagów), przykład:

Kopiuj
znacznik <b> pogrubi zaznaczony obszar <b> pogrubienie1 </b> =  <b> pobrubienie2 </b> 

W tym przypadku pierwszy znacznik nie powinien i nie może zostać zmieniony.
Obecnie przerobiłem kod DevExpress i chyba na tym pozostanę.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.