Avatar billede w13 Novice
13. oktober 2015 - 21:09 Der er 8 kommentarer og
1 løsning

Matche på nestede {}

Hej Eksperter

Jeg er reg.exp.-noob, og har et dertil relateret spørgsmål.

Jeg har p.t. den her expression og kode:
$regex = "/\\{(.*?)\\}/";
preg_match_all($regex, $s, $matches);

Den matcher på { og } og hvis man fx har strengen: Hello {world}.
så vil den returnere world.

Jeg vil dog rigtig gerne kunne neste mine {} og derved have sætninger såsom:
Hello {world of {warcraft}}.
og derved returnere både {warcraft} og world of {warcraft}.

Kan I hjælpe? :-/

På forhånd mange tak!

Med venlig hilsen
Tobias
Avatar billede arne_v Ekspert
13. oktober 2015 - 21:14 #1
Skift fra reluctant til greedy match og process matches rekursivt.
Avatar billede arne_v Ekspert
13. oktober 2015 - 21:27 #2
til inspiration:


<?php

// not good
$s = 'Hello {world of {warcraft}}.';
$regex = '/\{(.*?)\}/';
preg_match_all($regex, $s, $matches);
foreach($matches[1] as $match) {
    echo $match . "\r\n";
}

// maybe better
function process($s, $callback) {
    preg_match_all('/\{(.*)\}/', $s, $matches);
    foreach($matches[1] as $match) {
        $callback($match);
        process($match, $callback);
    }
}

function display($match) {
    echo $match . "\r\n";
}

$s = 'Hello {world of {warcraft}}.';
process($s, 'display');

?>

Avatar billede w13 Novice
13. oktober 2015 - 22:40 #3
Hej Arne

Tak for dit svar!

Det virker til dels. Dog ikke på fx den her sætning:

Du drikker {cola} med Lars i en {børnehave}.

Den returnerer nemlig:
Du drikker cola} med Lars i en {børnehave.

:(

Det tyder jo på, at den tager de to yderste klammer først, men det skal den ikke, når de inderste er }{ - kun hvis de er {}. Giver det mening?

Mvh. Tobias
Avatar billede arne_v Ekspert
14. oktober 2015 - 01:59 #4
Det giver mening, men jeg tror ikke at regex er det rette vaerktoej til opgaven.
Avatar billede arne_v Ekspert
14. oktober 2015 - 02:07 #5
Non regex kode:


<?php
function process($s, $callback) {
    $lvl = -1;
    $buf = array();
    for($i = 0; $i < strlen($s); $i++) {
        $c = $s[$i];
        switch($c) {
            case '{':
                $lvl++;
                $buf[$lvl] = '';
                break;
            case '}':
                $callback($buf[$lvl]);
                $lvl--;
                break;
            default:
                for($j = 0; $j <= $lvl; $j++) $buf[$j] .= $c;
                break;
        }
    }
}

function display($match) {
    echo $match . "\r\n";
}

process('Hello {world of {warcraft}}', 'display');
process('Du drikker {cola} med Lars i en {børnehave}.', 'display');

?>
Avatar billede w13 Novice
18. oktober 2015 - 22:20 #6
Den ser umiddelbart ud til at være i den rigtige retning!
Jeg har sat den til at returnere et array, så jeg kan replace de forskellige værdier.

Lige nu returnerer den:

Array
(
    [0] => warcraft
    [1] => world of warcraft
)

Men [1] skulle gerne være: world of {warcraft}

Kan du hjælpe med dén sidste rettelse? Jeg kan ikke helt gennemskue det, må jeg indrømme...

Mvh. Tobias
Avatar billede w13 Novice
09. april 2016 - 08:57 #7
Jeg lukker her. Vil du have point, Arne_V? :)
Avatar billede arne_v Ekspert
09. april 2016 - 16:15 #8
Jeg missede det sidste spoergsmaal.

men:


<?php
function process($s, $callback, $include = false) {
    $lvl = -1;
    $buf = array();
    for($i = 0; $i < strlen($s); $i++) {
        $c = $s[$i];
        switch($c) {
            case '{':
                if($include && $lvl >= 0) $buf[$lvl] .= '{';
                $lvl++;
                $buf[$lvl] = '';
                break;
            case '}':
                $callback($buf[$lvl]);
                $lvl--;
                if($include&& $lvl >= 0) $buf[$lvl] .= '}';
                break;
            default:
                for($j = 0; $j <= $lvl; $j++) $buf[$j] .= $c;
                break;
        }
    }
}

function display($match) {
    echo $match . "\r\n";
}

process('Hello {world of {warcraft}}', 'display');
process('Hello {world of {warcraft}}', 'display', true);
process('Du drikker {cola} med Lars i en {børnehave}.', 'display');
?>
Avatar billede arne_v Ekspert
09. april 2016 - 16:15 #9
og svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester