Edytor znaczników formatu tekstu - problem z Regex

Edytor znaczników formatu tekstu - problem z Regex
CL
  • Rejestracja:ponad 15 lat
  • Ostatnio:7 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:7 minut
  • Lokalizacja:Tuchów
  • Postów:12166
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:ponad 15 lat
  • Ostatnio:7 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:prawie 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:ponad 15 lat
  • Ostatnio:7 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:7 minut
  • Lokalizacja:Tuchów
  • Postów:12166
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:ponad 15 lat
  • Ostatnio:7 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ę.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)