[PHP] Regex voor splitsen soort unordered list werkt niet

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik onderhoud een website waar een hele lange lijst met veelgestelde vragen (FAQs) staat. Nu worden de vragen (bovenaan de pagina in een ordered list) en de antwoorden (onder de list) nog apart en handmatig bijgehouden, maar dit is erg onhandig.

Nu dacht ik dat de pagina makkelijker te onderhouden zou zijn, als de anchors bv. automatisch worden gegenereerd en je als beheerder vraag en antwoord bij elkaar kunt zien (in plaats van dat er 5 schermen scrollen tussen zitten).

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Ik wil nu dit format:

[faq]
  [hoe?]wat jou het beste lijkt
  [waarom?]omdat het kan
  [wanneer]elke dag
[/faq]

// omzetten in:
<ul>
  <li><a href="#answer-1">hoe?</a></li>
  <li><a href="#answer-2">waarom?</a></li>
  <li><a href="#answer-3">wanneer?</a></li>
</ul>

<a name="answer-1">wat jou het beste lijkt</a><br>
<a name="answer-2">omdat het kan</a><br>
<a name="answer-3">elke dag</a><br>

Hiervoor heb ik een functie nodig die de "bulletpoints" (hoe, waarom en wanneer) verwerkt. Aangenomen dat $text "[hoe?]wat jou het beste lijkt[waarom?]omdat het kan[wanneer]elke dag" is, dacht ik hieraan:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
function oml_faq_split_items($text) {
  $pattern = '/\[\*\]/';
  $items = preg_split($pattern, $text);
  $i = 1;
  foreach ($items as $question => $answer) {
    $i++;
    $section_1.= '<li><a href="#answer-'. $i .'">'. $question .'</a>';
    $section_2.= '<a name="answer-'. $i .'"><p>'. $answer .'<p>';
  }
  $output = '<ul>'. $section_1 .'</ul>';
  $output.= $section_2;
  return $output;

Zoals je ziet is mijn $pattern wat zielig. Mijn regex skills zijn niet genoeg om $text te splitten in de array zoals ik hem verder wil verwerken. Welke regex koning kan mij helpen?

Acties:
  • 0 Henk 'm!

  • mocean
  • Registratie: November 2000
  • Laatst online: 04-09 10:34
Ik vind je format wat onhandig. Het lijkt op ubb code, maar de ene tag sluit je wel af (faq) de andere niet (de vragen) en die bevat ook nog random teksten.

Dus het parsen zal wel kunnen lukken, maar niet met enkel regexps. Misschien wel met een boel str_pos en substr, maar dat wordt ook geen nette oplossing.

Probeer eens een xml format voor je faq. Of wellicht CSV dat kan ook wel makkelijk onderhoudbaar zijn.

Koop of verkoop je webshop: ecquisition.com


Acties:
  • 0 Henk 'm!

  • ErikKo
  • Registratie: Mei 2009
  • Laatst online: 17-09 18:39

ErikKo

Rippie

Ik gebruik voor dit soort problemen altijd de methode split.
Dit heeft als nadeel dat de string waar je op splitst in de tekst voor kan komen en dus je code kapot maakt.
Ik gebruik (in jouw geval) altijd het volgende:
PHP:
1
2
3
4
5
6
$faq = "wat jou het beste lijkt<+>omdat het kan<+>elke dag";
$faq_split = split("<+>", $faq);

// $faq_split[0] == Hoe?
// $faq_split[1] == Waarom?
// $faq_split[2] == Wanneer?

Acties:
  • 0 Henk 'm!

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

In de FAQ vind je een aantal relevante links en de basics van reguliere expressies. Daarmee zou je al een heel eind verder moeten komen dan hetgeen je nu hebt.

Performance is a residue of good design.


Acties:
  • 0 Henk 'm!

Verwijderd

Anders heb je van O'Reilly een kleine boekje genaamd: Regular Expression pocket reference. :)

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Het scheelt ook om even de juiste functies te gebruiken. Split lijkt me niet geschikt. Ik denk meer aan iets als:
PHP:
2
3
  preg_match_all('/\[([^\]]*+)\]([^[\r\n]*+)/', $text, $result);
  $items = array_combine($result[1], $result[2]);

Voor de rest heeft php een (net geupdate) aardige uitgebreide uitleg van preg.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
pedorus schreef op zaterdag 17 oktober 2009 @ 19:38:
Het scheelt ook om even de juiste functies te gebruiken. Split lijkt me niet geschikt. Ik denk meer aan iets als:
PHP:
2
3
  preg_match_all('/\[([^\]]*+)\]([^[\r\n]*+)/', $text, $result);
  $items = array_combine($result[1], $result[2]);
pedorus, thanks. Een klein vraagje:
code:
1
2
3
4
[iets]en dan wat tekst // werkt wel

[iets]
en dan wat tekst // werkt niet

Is het mogelijk de regex aan te passen zodat hij in beide gevallen werkt? (of zelfs wanneer er meerdere newlines tussen [iets] en de tekst zitten?). Of is het beter om alle spaces tussen "]" en de tekst eerst met php te stippen voordat de string ueberhaupt naar de regex gaat?
Voor de rest heeft php een (net geupdate) aardige uitgebreide uitleg van preg.
Ik ga zeker kijken. Hoop dat het te begrijpen is; ik geef toe dat ik meer dan eens begonnen ben aan regexen maar ben altijd na 2,3 pagina's afgehaakt omdat het vaak al snel overweldigend wordt :|

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Verwijderd schreef op zaterdag 17 oktober 2009 @ 20:29:
Is het mogelijk de regex aan te passen zodat hij in beide gevallen werkt? (of zelfs wanneer er meerdere newlines tussen [iets] en de tekst zitten?).
Ja, \s*+ toevoegen op het juiste punt.
Of is het beter om alle spaces tussen "]" en de tekst eerst met php te stippen voordat de string ueberhaupt naar de regex gaat?
Nee, dat lijkt me onhandig.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 17-09 20:07

MBV

je zou /m kunnen gebruiken als modifier, 'multi-line'. Maar als je verder niks doet met newlines is het een optie om ze er allemaal uit te slopen. De rest van de regex snap ik niet, maar mijn simpele versie werkte ook niet. Hier mijn poging 85 (trial&error FTW :Y):

code:
1
/\[?([^\]]+)\]\s*([^\[\]]+)\s*(\[|$)/m

Waarbij steeds de eerste waarde de 'titel' en de tweede waarde de tekst bevat, en de 3e genegeerd kan worden.
Gedocumenteerd:
Perl:
1
2
3
4
5
6
/\[?        #eerste teken. Hoeft er niet te zijn dankzij het afsluitende teken, dus het vraagtekentje.
([^\]]+)    #eerste groep: alles tot aan de ], minstens 1
\]\s*          #de afsluiting van de titel. plus whitespace
([^\[\]]+)   #de rest, tot de volgende titel of het einde
\s*(\[|$)       #whitespace, plus eerste teken van de volgende titel of het einde
/x


edit:
ook maar even \s op de goede plek gezet

[ Voor 7% gewijzigd door MBV op 17-10-2009 21:04 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
pedorus schreef op zaterdag 17 oktober 2009 @ 20:45:
Ja, \s*+ toevoegen op het juiste punt.
PHP:
1
preg_match_all('/\[([^\]]*+)\]\s*+([^[\r\n]*+)/', $text, $result);

Thanks!

@MBV: thanks, ik ga jouw oplossing ook bekijken, maar ben nu eerst aan het uitzoeken waarom pedorus zegt dat split hier niet de goede tool voor de job is... :)

[ Voor 40% gewijzigd door Verwijderd op 17-10-2009 21:48 ]


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Ik zou niet voor mijn eigen systeem van tags gaan, maar gewoon UBB/RML/whatever-dat-al-bestaat gebruiken en een parser van de plank trekken. Sowieso zijn regexen al snel niet handig of zelfs niet toereikend voor het parsen van geneste structuren. Wat in dit soort topics standaard geroepen wordt, is dat je waarschijnlijk een stackbased parser wilt.

[ Voor 45% gewijzigd door Confusion op 17-10-2009 22:16 ]

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Of je laat lekker alle syntax troep achterwege en explode op regels en op de eerste vraagteken. Zo, 23 seconden werk en de notatie kan bijna niet simpeler. Y:)

{signature}


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Precies, ik zie het hele probleem niet. Met een paar simpele explodes en str_replaces kun je dit heel snel omzetten naar hoe je de html wilt. Dat verder los van of dit een handige methode is van invoeren natuurlijk ;)

Wie had ook alweer die signature over regexes? :+

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 17-09 21:27

Creepy

Tactical Espionage Splatterer

Cartman! schreef op zondag 18 oktober 2009 @ 12:17:

Wie had ook alweer die signature over regexes? :+
O-)

En inderdaad: wat mij betreft gebruik je juist geen regexes op dit soort zaken te parsen. Exploden en gaan, of desnoods gewoon regel voor regel inlezen en states controleren (een simpele stack based parser dus, ook maar een paar regels code).

[ Voor 41% gewijzigd door Creepy op 18-10-2009 12:43 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Creepy schreef op zondag 18 oktober 2009 @ 12:42:
een simpele stack based parser dus, ook maar een paar regels code
Mm, die 2 regels wil ik zien. :Y) Overigens deed het me denken aan:
.oisyn schreef op dinsdag 13 oktober 2009 @ 00:07:
Euh, nee. Laat dit nou een typisch voorbeeld zijn van waar een regex juist goed uitkomt. En vertel me eens, hoe ga jij je stackbased-parser bouwen (naast het feit dat je stack in dit geval maar max 1 level diep is) zonder een regex die je string opdeelt in een tokenstream? Zelf met PHP code character voor character door de string heen lopen? En mocht je uiteindelijk naderhand een stackbased-parser nodig hebben, dan kun je je regex iets aanpassen en de parser gewoon toevoegen. Hij is op dit moment gewoon nog niet nodig, en het is tevens niet zo dat je code weg moet gooien op het moment dat je 'm wel nodig gaat hebben.
Een nog andere gedachte is om de boel gewoon netjes in een database op te slaan. Schijnt zelfs vrij gebruikelijk te zijn, en dan kunnen je vragen en antwoorden ook gewoon alle tekens bevatten. :)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 17-09 21:27

Creepy

Tactical Espionage Splatterer

Dat "paar" moet je niet zo letterlijk nemen ;)
Maar regel voor regel inlezen, een [whatever] ombouwen tot UL en een ingesprongen [whatever2] ombouwen tot een LI met een link en ergens nog een anchor invoegen lijkt me zo spanned nu niet. Misschien een regexp om de items die een LI moeten worden uit elkaar te trekken alhoewel dat ook prima zonder kan.
Maar alleen 1 (of 2) regexen die dat in z'n geheel moeten doen heeft absoluut niet mijn voorkeur nee.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-08 20:35
ErikKo schreef op zaterdag 17 oktober 2009 @ 18:53:
Ik gebruik voor dit soort problemen altijd de methode split.
Wellicht dat je dan beter explode kan gaan gebruiken, want zoals de PHP manual (zie je eigen link) al aangeeft is split deprecated in PHP 5.3 en wordt het verwijderd in PHP 6.

If I can't fix it, it ain't broken.


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 17-09 20:07

MBV

Jammer dat Explode in PHP niet werkt met regexes zoals java ;) Verder heb je vaak wel gelijk, maar vind ik het soms leuk om dit soort huiswerkopgaves met een one-liner op te lossen, zoals ik het soms een sport vindt om iets met SQL te doen wat met 3 regels imperatieve code simpeler te doen is :P

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

MBV schreef op zondag 18 oktober 2009 @ 21:30:
Jammer dat Explode in PHP niet werkt met regexes zoals java ;)
Dan neem je maar preg_split :P
Pagina: 1