Toon posts:

Simpel markuptaaltje schrijven (zonder regexps)

Pagina: 1
Acties:

Verwijderd

Topicstarter
Voor een forum wil ik een simpel markuptaaltje gebruiken met tags als {b} en {i}

Met reguliere expressies kan dat makkelijk tuurlijk, maar ik wil wel eens een simpel parsertje schrijven voor de markup van de messages.

Het is natuurlijk het makkelijkst om de tekst eerst in een array te stoppen met twee soorten elementen:

- tags, en andere tekst waar iets mee moet gebeuren zoals ascii-smileys die grafisch gemaakt moeten worden;

- de eigenlijke tekst;

Dat is gebeurd. Nu wil ik de array inlezen en html genereren.
Voor wat betreft de tags met een openende en sluitende versie (zoals {i}{/i}) dacht ik: ik zet de tags gewoon op een stack, en onderwijl genereer ik html waarbij ik alleen af en toe naar de stack hoef te kijken om te zien of ik alweer een openende en een sluitende tag hoef te schrijven.

Maar ik zit met een probleem in bijvoorbeeld onderstaande string:

dit is een {b} tekst dit {b} is een {/b} tekst

Ik wil dat hij dit resultaat genereert in html:

dit is een <b> tekst dit {b} is een </b> tekst

Maar hoe weet ik bij de tweede {b} al op het moment dat ik html genereer dat hij geen bijbehorende sluitende tag heeft? Niet dus..

Ik heb het idee alsof ik met een probleem bezig ben wat door heel veel mensen al lang op een heel handige manier is opgelost. Weet iemand misschien wat (grofweg) de handigste manier is om dit aan te pakken?
Of heeft iemand een link?

Alvast bedankt.

  • TheDane
  • Registratie: Oktober 2000
  • Laatst online: 23-08 15:30

TheDane

1.618

waarom zonder regex ? 't feit dat je regex kan gebruiken maakt 't juist simpel imho

Verwijderd

Topicstarter
Wat zeg ik nou..

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je kan dan toch gewoon van links naar rechts scannen, en als je een {b} tegen komt dan zet je een vlag: "{b} open" en output je een tag. Dan ga je verder, kom je weer een {b} tegen dan is die al "open" en kan dus genegeerd worden. Op het moment dat je een {/b} tegen komt kijk je of {b} wel "open" was, zo ja schrijf je een tag en zet je {b} op "closed" anders negeer je het.

Zoiets?

  • TheDane
  • Registratie: Oktober 2000
  • Laatst online: 23-08 15:30

TheDane

1.618

je zegt: een of andere combinatie van woorden met daarin zonder, regex, simpel

mijn vraag: waarom zonder regex :?

maagoed, heb zelf ooit iets gemaakt die substrings zoekt, dus vanaf een of andere gegeven string {b} tot en met {/b}
dan van die string de eerste 3 en laatste 4 karakters afhalen,
en pre + appenden van de eigenlijke tags,.

maargoed, da's pretty darn rudimentair, en werkt dus ook niet of per ongeluk als je gaat nesten

[ Voor 10% gewijzigd door TheDane op 10-02-2003 15:50 ]


Verwijderd

Topicstarter
Ja maar dan gaat dit niet goed.

the quick {b} brown {b} fox {/b} jumps over {/b} the lazy dog

terwijl dat toch een "welgevormde" en "correcte" string is..

En er moet een handige manier voor zijn, want webbrowsers kunnen prima omgaan met dingen als:

- orphan tags;
- tags die door elkaar heen niet op de correcte manier worden afgesloten zoals
the quick {b} brown {i} fox {/b} jumps over the {/i} lazy dog;
- meerdere keren dezelfde tag genest (wat dus overbodig is, maar soms zal voorkomen, met name als je met gegenereerde html te maken hebt):
the quick {b} brown {b} fox jumps {/b} over the {/b} lazy dog

En ook de parser van dit forum maakt als ik me goed herinner geen gebruik van reguliere expressies, maar parst de messages ook zelf.

[ Voor 67% gewijzigd door Verwijderd op 10-02-2003 15:54 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Dan doe je geen bool maar een integer, die je steeds ophoogt als je een {b} tegen komt. close-tag schrijven als ie op 0 komt?

  • TheDane
  • Registratie: Oktober 2000
  • Laatst online: 23-08 15:30

TheDane

1.618

Verwijderd schreef op 10 February 2003 @ 15:51:
Ja maar dan gaat dit niet goed.

the quick {b} brown {b} fox {/b} jumps over {/b} the lazy dog
klopt :)

maar je zou vanaf je {/b} tag natuurlijk gewoon weer opnieuw kunnen beginnen met 't zoeken naar een substring '{b}..{/b}' .. dan gaat alleen dit (inderdaad) mis:

{b}bla die {b} bla {/b} ya die ya {/b} die ja

maar dat kun je weer oplossen door (zoals gezegd) alleen af te sluiten als je teller weer op 0 staat, dus als je stack weer leeg is

Verwijderd

Topicstarter
maar dan gaat dit geval niet goed:

the quick brown {b} fox jumps {b} over the lazy {/b} dog

hier wil ik dat de middelste tag "niet verwerkt" wordt maar gewoon als tekst wordt afgedrukt.

Gewenst resultaat dus
the quick brown <b> fox jumps {b} over the lazy </b> dog

Maar hoe weet ik dan dat die middelste niet afgesloten wordt..

[ Voor 12% gewijzigd door Verwijderd op 10-02-2003 15:58 ]


  • TheDane
  • Registratie: Oktober 2000
  • Laatst online: 23-08 15:30

TheDane

1.618

Verwijderd schreef op 10 February 2003 @ 15:58:
maar dan gaat dit geval niet goed:

the quick brown {b} fox jumps {b} over the lazy {/b} dog

hier wil ik dat de middelste tag "niet verwerkt" wordt maar gewoon als tekst wordt afgedrukt.

Gewenst resultaat dus
the quick brown <b> fox jumps {b} over the lazy </b> dog

Maar hoe weet ik dan dat die middelste niet afgesloten wordt..
dat weet je in principe niet ... maar het lijkt me dat je als je een sluit-tag tegenkomt, dat je dan gewoon alle voorgaande bijbehorende elementen dus _alle_ {b} tags uit je stack moet poppen,.

dan is er dus geen match meer als je nog (per ongeluk) een {/b} tegenkomt, en blijft de middelste {b} in je tekst dus gewoon {b} ... en je laatste {/b} blijft dan gewoon {/b}

ik weet alleen niet of je dat wilt ..

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:08
Begin eerst eens met het opsplitsen van je string in tokens: tags en letterlijke tekst. Dat zou je prima met een reguliere expressie kunnen doen (splitten op "\{.+?\}" ofzoiets). Nu heb je bij voorbeeld een array met daarin ("the quick brown ", "{b}", " fox jumps ", "{/b}", " over the lazy ", "{/b}", "dog").

Je kunt nu de tekst gaan parsen door de array te doorlopen en elke keer te beslissen wat je met het huidige element wil doen. Ik kan me voorstellen dat dat in dit voorbeeld zo gaat:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$b_open = false;
foreach($token_array as $token)
{
    if( ($token == "{b}") && ($b_open == false) )
    {
        print("<b>");
        $b_open = true;
    }
    else
    if( ($token == "{/b}") && ($b_open == true) )
    {
        print "</b>";
        $b_open = false;
    }
    else
    {
        print $token;
    }
}


Bij gebrek aan specifieke informatie over welke programmeertaal je wilt gebruiken, heb ik maar even ge-PHP-t. ;) Op dit thema zijn allerlei variaties mogelijk; je kunt misschien forceren dat de laatst geopende tag het eerst gesloten moet worden (zodat "{b}{i}xxx{/b}{/i}" illegaal is) of dat bepaalde tags genest mogen worden (waardoor je een teller in plaats van een boolean moet bijhouden). Ook kun je (vooral in andere talen dan PHP) een meer generieke parser schrijven, waardoor je geen groot if/else blok hoeft te maken.

Meer van dit soort details kun je wel met Google vinden.

Verwijderd

Topicstarter
Zoeken naar substrings kan ik niet gaan doen. Dat zijn zulke tijdrovende operaties dat ik net zo goed gelijk reguliere expressies kan gaan gebruiken.

Dan ben ik alleen maar bezig met het schrijven van een trage, omslachtige en waarschijnlijk niet werkende implementatie van mijn eigen reguliere expressie parser...

Verwijderd

Topicstarter
Tokenisen doe ik al. De array bestaat inderdaad uit elementen die of tag, of "naturel" tekst zijn.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:08
Een simpele reguliere expressie toepassen is niet zo kostbaar, hoor. Zeker niet als 't gaat om teksten van maximaal een paar kilobyte, zoals op een forum het geval is. Het kritieke punt is hoe ingewikkeld je je reguliere expressie maakt; de voorgestelde variant is doodeenvoudig.

Welke taal gaat 't trouwens om?

Verwijderd

Topicstarter
Soultaker schreef op 10 February 2003 @ 16:07:

Bij gebrek aan specifieke informatie over welke programmeertaal je wilt gebruiken, heb ik maar even ge-PHP-t. ;)
Ja, dat is de bedoeling :) eigenlijk dat, en in iets mindere mate perl, zijn ideaal voor het schrijven van een forum.
Op dit thema zijn allerlei variaties mogelijk; je kunt misschien forceren dat de laatst geopende tag het eerst gesloten moet worden (zodat "{b}{i}xxx{/b}{/i}" illegaal is)
Ik wil niks illegaal maken, maar gewoon steeds het meest logische doen, net als een willekeurige webbrowser..
of dat bepaalde tags genest mogen worden (waardoor je een teller in plaats van een boolean moet bijhouden).
Maar ik wil alles kunnen nesten..

Verwijderd

Topicstarter
Zit te denken over bijvoorbeeld een oplossing met een recursieve functie.
Maar dat wordt nog niet makkelijk te programmeren..

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:08
Hmm, wil je die {b} tags nu wel of niet kunnen nesten?

Verwijderd

Tja, je weet alleen wat je niet wilt, maar niet wat je wel wilt.

Ik zou zeggen: schrijf eens een heleboel variaties op, en wat jou code zou moeten renderen.
Dan kan je pas zien wat en waar, wel en niet genegeerd moet worden.

Verwijderd

Topicstarter
ja, ik wil..

- tags kunnen nesten (alle voorkomende tagparen)
- tags kunnen afsluiten in een andere volgorde dan waarin ik ze opende
eerste {b} tweede {i} derde {/b} vierde {/i} snap je
- orphan tags niet verwerken, maar gewoon als tekst afdrukken.
bijvoorbeeld deze tag {b} wel verwerken, maar {b} deze niet, als er maar een van {/b} deze is

Verwijderd

Ok, je hebt voorbeelden opgeschreven. Wat moet er bij deze dingen nu precies gegenereerd worden.
Vooral bij de moeilijke gevallen van scheef geneste en dubbel geneste tags.

Verwijderd

Topicstarter
Verwijderd schreef op 10 February 2003 @ 16:57:
Dan kan je pas zien wat en waar, wel en niet genegeerd moet worden.
Overzicht lijkt me gegeven..

Verwijderd

Nee helemaal niet. Je moet ook nadenken wat er in HTML uit moet komen. Probeer het maar eens op te schrijven en dan zie je vanzelf waarom je niet alles kan willen.

Verwijderd

Topicstarter
- tags kunnen nesten (alle voorkomende tagparen)

Dus als identieke tags genest worden, twee, drie of vier keer, worden ze gewoon verwerkt.
bold tags binnen bold tags zijn toegestaan; alles wordt dan gewoon bold.
Verschillende tags nesten is sowieso toegestaan. (bold tags binnen italics tags bijvoorbeeld)

- tags kunnen afsluiten in een andere volgorde dan waarin ik ze opende

Als je een italics tag opent en daarna een bold tag, daarna eerst de italics tag afsluit en daarna de bold tag, worden alle tags verwerkt, op zo'n manier dat geopende tags open blijven tot ze door een bijbehorende sluit-tag worden gesloten, ongeacht wat daartussen aan openende en sluitende tags zit.

- orphan tags niet verwerken, maar gewoon als tekst afdrukken.

Als openende tags geen bijbehorende sluitende tags hebben, en vice versa, worden ze afgedrukt als tekst.

bijvoorbeeld deze tag {b} wel verwerken, maar {b} deze niet, als er maar een van {/b} deze is

Voor de evaluatie van tag paren wordt dus niet gekeken naar de openende tag die het dichtst bij de sluitende tag staat, maar de eerste openende tag die een toestand doet ingaan.

Verwijderd

Je verteld te vaak hetzelfde. Probeer nu eens zoiets op te schrijven:
{b} Deze {b} tekst {/b} moet {/b} bold => <b>Deze tekst moet</b> bold
{b} Deze {b} tekst {/b} moet bold => <b>Deze {b} tekst</b> moet bold

Enzovoort. Je ziet al dat hier een probleem ontstaat: je wil enerzijds dat foutief geneste tags niet omgezet worden, en anderzijds wel (of zelfs helemaal weggehaald) (Waarom zou de tweede {b} andere uitvoer genereren in de twee bovenstaande gevallen?)

Je wil dus iets dat niet kan, en als ik je topic titel lees (het woord SIMPEL) zou ik het zo houden: foutief genest is fout, en de resultaten zijn onvoorspelbaar :P

Verwijderd

De tweede {b} in jouw tweede geval wordt letterlijk afgedrukt omdat hij geen sluitende tag heeft. Zoals ik het opgeschreven heb, klopt het prima! Je wilt het geloof ik niet snappen..

Die tweede tag in het tweede geval zie ik ook niet als 'foutief genest' maar als helemaal niet genest.. want het is geen deel van een paar

Er zijn ook minimaal twee gevallen waarin het al precies zo werkt als ik omschreven heb.

1. Alle gangbare browsers - het html-equivalent dan he, dus met < en >
Het enige triviale verschil is dat orphan tags door browsers niet letterlijk worden afgedrukt maar worden genegeerd

2. Dit forum. Probeer maar. hier kan je het nalezen.

[ Voor 2% gewijzigd door Verwijderd op 10-02-2003 19:52 . Reden: Even thuis verder schrijven. ]


  • Sendy
  • Registratie: September 2001
  • Niet online
Nou ja zeg. Kijk nog eens terug naar mijn voorbeeld(jes).
Als je een simpele parser bouwt (zonder vooruit te kijken) dan zit er tot de laatste {/b} geen verschil in de twee expressies. Hoe kan de uitvoer dan anders zijn?!?

Nee, je moet een ingewikkelder parser schrijven dus.

  • MisterData
  • Registratie: September 2001
  • Laatst online: 24-08 09:53
Stackbased-UBBlike-parser: http://dev.trag.nl/ojc/include/tpltest.php :) De source staat op www.codebase.nl :)

Verwijderd

Wil je niet gewoon domweg een regex parser maken?
En vervolgens een nodelist?

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 19:16

Gerco

Professional Newbie

Mja, stackbased gaat ook prima, zie http://achelois.tweakers.net/~acm/parse/

Alleen voldoet deze niet aan de vereiste simpel geloof ik.

[ Voor 40% gewijzigd door ACM op 09-10-2007 22:41 . Reden: vulcanus.its.tudelft.nl is niet meer ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!

Pagina: 1