IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

preg_match avec sous-masques optionnels et non ordonnés ?


Sujet :

Langage PHP

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 100
    Points : 161
    Points
    161
    Par défaut preg_match avec sous-masques optionnels et non ordonnés ?
    Bonjour,

    Je suis actuellement en train de travailler sur un programme PHP permettant de convertir des AVH (ou "visual novels") créée sous Ren'Py. Ce dernier logiciel utilise un langage très proche du Python (j'en avais déjà parlé dans ce post).

    Ren'py utilise le code suivant pour faire apparaître un personnage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    show Toto at left with dissolve
    Ce qui signifie "montrer Toto à gauche avec l'animation "dissolve".

    Il faut donc que je récupère trois arguments :
    • l'objet à afficher : Toto
    • la position : left
    • l'animation : dissolve

    Jusqu'ici, tout va bien, je pourrais facilement récupérer les trois arguments grâce aux expressions régulières et la fonction preg_match().

    Sauf que ce n'est bien entendu pas si facile (sinon, je ne posterais pas là), vu qu'à part le premier (l'objet à afficher), les arguments sont optionnels et que leur ordre est libre. Les codes suivants sont ainsi tous valides :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    show Toto
    show Toto at left
    show Toto with dissolve
    show Toto at left with dissolve
    show Toto with dissolve at left
    Et pour simplifier le tout, il n'y a pas que deux arguments optionnels mais six (with, as, at, behind, onlayer, zorder).
    Pour l'instant, le seul moyen que j'ai trouvé, c'est de faire un strpos pour chaque paramètre, de les classer par ordre d'apparition et de spliter ensuite le tout. Mais cela me semble bien compliqué, peu élégant et assez peu optimisé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    private function explode_param($string){
        $params = array(); // le tableau associatif des paramètres à retourner
        $positions = array(); // à quel endroit scinder la string
        $prefixes = array('with', 'as', 'at', 'behind', 'onlayer', 'zorder');
        foreach($prefixes as $prefixe) {
            $pos = strpos($string, ' '.$prefixe.' '); //on ajoute l'espace devant et après pour être sûr de ne pas sélectionner une partie d'un mot
            if ($pos !== false){
                $positions[] = $pos;
            }
        }
        // le paramètre with peut être présent deux fois
        if(strpos($string, ' with ') != strrpos($string, ' with ')){ // si la dernière occurence est différente de la première
            $positions[] = strrpos($string, ' with ');
        }
        sort($positions); // on classe les arguments par ordre d'apparition
        foreach($positions as $key=>$pos) {
            // on isole la chaîne de caractère dédiée à ce paramètre
            if(isset($positions[$key+1])){
                $length = $positions[$key+1] - $pos;
                $substring = trim(substr($string, $pos, $length));
            }else{
                $substring = trim(substr($string, $pos));
            }
            // si la chaîne comporte au moins deux mots
            if(strpos($substring, ' ')!==false){
                $nom = strstr($substring, ' ', true); // le nom du paramètre est le premier mot de la chaîne
                $valeur = strstr($substring, ' '); // la valeur est le reste
                if($nom=='with' && isset($params[$nom])) $nom .= '2'; // s'il y a deux paramètres with
                $params[$nom] = $valeur;
            }
        }
        return $params;
    }
    Est-il possible de faire cela grâce à une expression régulière (ou un autre moyen) ?

    Un peu comme la fonction suivante, mais avec des sous-masques optionnels et non ordonnés :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    preg_match('#^show (?P<nom>\w+) with (?P<transition>\w+) at (?P<position>\w+)#i', $string, $matches)
    Merci beaucoup d'avoir pris le temps de lire ce message et peut-être d'y répondre,
    Korbn, aka Dr Schizo

  2. #2
    Invité
    Invité(e)
    Par défaut
    À la grosse louche, un truc comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    preg_match('#^show (?<nom>\w+)(?:(?: with (?<with>\w+))|(?: as (?<as>\w+))|(?: at (?<at>\w+))|(?: behind (?<behind>\w+))|(?: onlayer (?<onlayer>\w+))|(?: zorder (?<zorder>\w+)))+$#i', "show toto behind blah", $matches);
    ps: les masques nommés ?<name> sont utilisables à partir de PHP 5.2.2.

  3. #3
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Je ne suis pas certains que les exemples que tu donnes soient vraiment représentatif de la situation, car après un rapide coup d'œil sur la documentation de Ren'Py, je me suis rendu compte que dans un script:
    • il n'y a pas que la commande show
    • les commandes ne sont pas forcément en début de ligne (donc on ne peut pas utiliser l'ancre ^
    • le nom d'un sujet peut être constituer de plusieurs mots:Toto content
    • une commande complète avec ses options peut s'étendre sur plusieurs lignes.


    D'autre part, ton objectif semble assez obscure, tu dis vouloir convertir des scripts réalisés pour Ren'Py, mais les convertir en quoi et pour quoi faire?
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 100
    Points : 161
    Points
    161
    Par défaut
    Merci bobe, je vais essayer cela ! J'utilise déjà les masques nommés pour récupérer les dialogues qui sont sous la forme suivante : toto "Hello world!"

    il n'y a pas que la commande show
    C'est l'exemple que je donne, mais ce problème concerne effectivement les commandes show, hide et scene. Il y a effectivement de nombreuses autres commandes à traduire et c'est un travail de longue haleine !

    les commandes ne sont pas forcément en début de ligne (donc on ne peut pas utiliser l'ancre ^
    Avant de convertir les commandes, le script les isole une à une.

    une commande complète avec ses options peut s'étendre sur plusieurs lignes.
    Idem, le script regroupe déjà les commandes complète sur une seule ligne avant de les traiter.

    le nom d'un sujet peut être constituer de plusieurs mots:Toto content
    C'est vrai. Mais il suffit de remplacer le "\w" par "\w " ou "[a-zA-Z_0-9 ]", non ?

    ton objectif semble assez obscure, tu dis vouloir convertir des scripts réalisés pour Ren'Py, mais les convertir en quoi et pour quoi faire?
    Je te rassure tout de suite : toute conversion est bien entendu faite avec l'accord des auteurs.

    Ren'Py est la référence en création de visual novels. C'est de très loin l'outils le plus utilisé par les créateurs.

    Mon objectif est dans un premier temps de publier des jeux au cas par cas sur le site de mon moteur et peut-être un jour de permettre aux inscrits de publier directement leurs propres jeux. S'il est actuellement possible de créer entièrement un jeu grâce à mon éditeur, cela demande des mois de travail (écriture, illustration...) pour un résultat incertain. Cela m'est ainsi arrivé plusieurs fois qu'un scénariste abandonne un projet en cours de route, faute de temps ou d'envie. Pour un simple développeur comme moi, le moyen le plus rapide de publier des jeux - et de démontrer par la même les capacités du moteur - reste donc de proposer aux auteurs de convertir leurs jeux déjà terminés. Surtout qu'il existe déjà de nombreux jeux formidables créés sous Ren'Py !

    Je travaille ainsi actuellement sur la conversion du jeu Fetish:Wanted, avec l'autorisation de son auteure, bien entendu.

    Je prévois aussi de mettre en place la conversion automatique vers Ren'Py, afin de rassurer les auteurs qui envisageraient d'utiliser mon framework. Ils pourront ainsi à tout moment convertir leur jeu sous Ren'Py et ainsi ne pas être dépendant de mon moteur (et de son futur bien plus incertain que celui du très implanté Ren'Py).

    J'espère avoir répondu à ta question !

Discussions similaires

  1. [RegEx] Problème avec assertion et sous masque
    Par tintin72 dans le forum Langage
    Réponses: 3
    Dernier message: 25/06/2012, 18h58
  2. Réponses: 2
    Dernier message: 18/05/2007, 11h09
  3. suppression avec sous requête conditionnelle
    Par melmel dans le forum Requêtes
    Réponses: 8
    Dernier message: 18/03/2004, 23h20
  4. Ping sous protocole TCP (et non UDP)
    Par ovdz dans le forum Développement
    Réponses: 2
    Dernier message: 19/06/2003, 14h10
  5. flashMX pb avec les masques
    Par annsoo dans le forum Flash
    Réponses: 2
    Dernier message: 12/05/2003, 12h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo