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 :

Scinder une longue chaine en plusieurs parties


Sujet :

Langage PHP

  1. #1
    Membre actif
    Inscrit en
    Octobre 2005
    Messages
    908
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 908
    Points : 271
    Points
    271
    Par défaut Scinder une longue chaine en plusieurs parties
    Bonjour,

    dans un projet de génération d'un PDF (via PHP + mPDF), j'ai un souci de pagination car je dois intégrer un saut de page lorsque mon texte atteint le bas de page.
    J'ai actuellement trouvé (me semble-t-il) le bon pattern regex pour couper intelligemment mon texte à savoir : scinder au retour chariot avant les 300 caractères MAX:
    Le problème que je rencontre c'est lorsque le texte contient beaucoup de retour chariot... je souhaite donc rajouter à mon pattern la condition de 5 lignes par capture MAX.
    Dans l'exemple suivant je souhaite une fin de capture après chaque ___
    > https://regex101.com/r/f1UpJp/1

    (dans mon projet les limites réelles sont de 44 RC et 2300 caractères MAX)

    Quelqu'un aurait-il les compétences pour optimiser ma regex ?
    Merci d'avance !

  2. #2
    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 te propose une solution que je qualifierais pour l'instant de théorique (car pas testée en situation réelle avec la longueur de ton texte).

    Elle consiste à utiliser une capture de la fin du texte suite à l'une des deux conditions pour contraindre l'autre condition qui doit vérifier que la partie capturée est bien à sa suite. Concrètement ça donne ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ~(*napla:.{1,300}$\R?(.*\z))(?>\N*\R?){0,5}(?=\1)~ums
    demo

    L'astuce consiste ici à placer l'une des conditions dans un test avant non-atomique (non-atomic positive lookahead, soit "napla"). Contrairement à test avant normal qui lui est naturellement atomique (le moteur de regex ne reviendra pas pour tester d'autres possibilités pour la sous pattern contenue dans cette assertion), le test avant non-atomique permet d'essayer plusieurs possibilités. Donc si après (?>\N*\R?){0,5}, la fin du texte est différente que celle capturée par (.*\z), autrement dit si (?=\1) échoue, le moteur de regex amorcera son backtracking qui pourra aller jusqu'à réduire le nombre de caractères consommés par .{1,300} pour tester une autre possibilité.

    Si du fait du nombre de caractères en situation réelle cette solution devait échouer, je te conseille de lire 300 caractères, de compter les sauts de lignes, puis au cas où de scinder au 5e saut de ligne pour adjoindre le reste à la prochaine lecture, le tout en bon vieux code.

    NB: tu peux avantageusement remplacer .{1,300} (qui consommera de 1 à 300 points de code) par \X{1,300} (qui consommera de 1 à 300 graphèmes). En effet, un caractère suivie d'un ou plusieurs caractères combinants (comme une lettre suivie de ses accents par exemple) comptera pour plus d'un point de code, mais ne comptera que pour un seul graphème.

    Pour augmenter la scalabilité de la pattern, tu peux éventuellement faire le pari que les 1000 ou 10000 prochains caractères suivant une condition ne seront jamais les mêmes et remplacer .*\z par .{0,10000}+, ce qui évite au moteur de regex d'aller jusqu'à la fin du texte. (Le gain de temps est considérable si le texte est long)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ~(*ANYCRLF)(*BSR_ANYCRLF)
     (?* \X{1,300} $ \R? (.{0,10000}+) )
     (?> \N* \R? ){1,5}  (?=\1)
    ~umsx
    demo 2
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  3. #3
    Membre actif
    Inscrit en
    Octobre 2005
    Messages
    908
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 908
    Points : 271
    Points
    271
    Par défaut


    whoua ! truc de fou... je vais mettre la journée à comprendre ton pattern !
    les premiers tests sont concluant la pagination semble bien s'effectuer à présent...

    effectivement sur mon plus gros test environ 25000 caractères je passe de 19500 étapes / 35ms à 18000 étapes / 12ms !

    je continue mes tests et reviens ici.
    En tout cas un ÉNORME MERCI @CosmoKnacki pour cette aide hyper pointue !

Discussions similaires

  1. Comment découper une adresse postale en plusieurs parties
    Par arnaudperfect dans le forum Langage
    Réponses: 12
    Dernier message: 18/08/2008, 23h31
  2. Réponses: 1
    Dernier message: 15/12/2006, 20h07
  3. Réponses: 10
    Dernier message: 17/05/2006, 11h50
  4. Separer une page HTML en plusieurs parties
    Par cedre22 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 01/02/2006, 14h56
  5. Découper une longue chaine
    Par lili_bzh dans le forum Linux
    Réponses: 13
    Dernier message: 23/01/2006, 18h08

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