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 :

plusieurs occurrences échappées dans une chaine délimitée


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    développeur web amateur
    Inscrit en
    Janvier 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : développeur web amateur
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2018
    Messages : 40
    Points : 35
    Points
    35
    Par défaut plusieurs occurrences échappées dans une chaine délimitée
    Bonjour,
    Je recherche, dans une chaine CSV, toutes les occurrences du caractère servant à l'échappement du caractère de séparation des champ, présent dans un champ texte délimité.

    le contexte est :

    PHP
    le caractère d'échappement est un caractère imprimable ascii simple (asc 33 à 126 pour faire court) (l'antislash (5C16, 9210) pour l'exemple.
    le caractère de séparation des champs aussi (le point-virgule (3B16, 5910) pour l'exemple)
    le champ texte contenant cette séquence est toujours délimité par un caractère de type guillemet (j'en ai trouvé 24 formes différentes en utf8) (guillemet double (2216, 3410) pour l'exemple).

    Les chaînes à tester sont les exemples variés suivants :
    "Laurent TOGIER";"19\; Rue Bréa";75006;PARIS ( 2 chaînes délimitées sans occurrence pour la première, une occurrence au milieu dans la seconde)
    Laurent TOGIER;"\; Rue Bréa";75006;PARIS (1 occurrence au début du champ délimité)
    Laurent TOGIER;"19\;";75006;PARIS (1 occurrence à la fin du champ délimité)
    Laurent TOGIER;"\;";75006;PARIS (1 occurrence seule dans le champ délimité)
    Laurent TOGIER;"19\; Rue\; Bréa";75006;PARIS (deux occurrences au milieu d'un champ délimité)
    Laurent TOGIER;"\;\;";75006;PARIS (deux occurrences seules dans un champ délimité)

    la regex : /".*?([^"]);.*?"/ me permet de repérer toutes les PREMIERES occurrences du caractère d'échappement dans le champ texte délimité,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $chaines = '"Laurent TOGIER";"19\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"19\;";75006;PARIS
    Laurent TOGIER;"\;";75006;PARIS
    Laurent TOGIER;"19\; Rue\; Bréa";75006;PARIS
    Laurent TOGIER;"\;\;";75006;PARIS';
    $dlmtTxt = '"';
    $sepChmp = ';';
    $rgxEsc =  "/$dlmtTxt.*?([^$dlmtTxt])$sepChmp.*?$dlmtTxt/";
    preg_match_all($rgxEsc, $chaines, $m);
    $escp = [];
    foreach($m[1] as $v) { ...
    Je pensais que la regex /".*?(([^"]);.*?)+"/ me permettrait d'avoir toutes les occurrences dans $m[2], alors qu'elle ne me permet que de voir la dernière occurrence dans chaque champ texte concerné.

    Pourriez-vous svp m'aider ?
    une indication, un signe, une piste vers la solution, seront les bienvenus.
    Merci par avance,
    Roland

  2. #2
    Membre habitué Avatar de daniel61
    Inscrit en
    Décembre 2006
    Messages
    139
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 139
    Points : 169
    Points
    169
    Par défaut
    Bonjour, dans l'exemple le caractère recherché est toujours échappé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var_dump(substr_count($chaines, "\\$sepChmp")); // 8
    Mais dans le format CSV le caractère séparateur n'a pas à être échappé s'il est encadré, par contre le caractère d'encadrement doit toujours l'être s'il n'encadre pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var_dump(substr_count(implode(str_getcsv($chaines, $sepChmp, $dlmtTxt)), $sepChmp)); // 8
    Le cas détestable pour tester un code serait selon moi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    debut;"...;...\"...;...";fin
    même là je vois toujours pas la nécessité de refaire ce que str_getcsv() sait déjà faire avec finesse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var_dump(substr_count(implode(str_getcsv('debut;"...;...\"...;...";fin', ';')), ';')); // 2

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    développeur web amateur
    Inscrit en
    Janvier 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : développeur web amateur
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2018
    Messages : 40
    Points : 35
    Points
    35
    Par défaut
    Bonjour Daniel,

    Merci de ta réponse,

    en réponse aux points que tu cites :
    à ma connaissance, dans un fichier csv, si délimiteur de texte est présent à l'intérieur d'un champ de texte, il est alors doublé (mais pas échappé) cad le texte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    il a dit "aie" en criant
    sera enregistré comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "il a dit ""aie"" en criant"
    .

    Je traite divers fichiers CSV (en fait portant cette extension), d'origines diverses, exotiks et variées et je vois passer tout et n'importe quoi comme séparateurs d'enregistrement, de champ, délimiteur de texte et caractère d'échappement.

    La plupart du temps, les séparateurs ne sont pas échappés à l'intérieur d'un champ texte délimité, mais pour les quelques restant (cad avec séparateurs échappés dans un champ texte délimité), j'aimerais qd même pouvoir les repérer autrement qu"en regardant le fichier.

    de là l'utilité du machin sur le plan de travail...

    str_getcsv est complètement à l'ouest qd le séparateur d'enregistrement est VT, celui des champs est "§" et le délimiteur est ` ... et je ne te parle pas des caractères unicode sur plusieurs octets.

    Aurais-tu une idée pour que ma regex repère toutes les occurences ?
    Dans quelle direction dois-je chercher

  4. #4
    Membre habitué Avatar de daniel61
    Inscrit en
    Décembre 2006
    Messages
    139
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 139
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par RolandGautier Voir le message
    à ma connaissance, dans un fichier csv, si délimiteur de texte est présent à l'intérieur d'un champ de texte, il est alors doublé (mais pas échappé) cad le texte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    il a dit "aie" en criant
    sera enregistré comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "il a dit ""aie"" en criant"
    .

    Je traite divers fichiers CSV (en fait portant cette extension), d'origines diverses, exotiks et variées et je vois passer tout et n'importe quoi comme séparateurs d'enregistrement, de champ, délimiteur de texte et caractère d'échappement.

    La plupart du temps, les séparateurs ne sont pas échappés à l'intérieur d'un champ texte délimité, mais pour les quelques restant (cad avec séparateurs échappés dans un champ texte délimité), j'aimerais qd même pouvoir les repérer autrement qu"en regardant le fichier.
    Correct, j'aurais dû lire la documentation c'est dans l'encadré... honte à moi mais le caractère d'échappement est aussi toléré.

    Citation Envoyé par RolandGautier Voir le message
    str_getcsv est complètement à l'ouest qd le séparateur d'enregistrement est VT, celui des champs est "§" et le délimiteur est ` ... et je ne te parle pas des caractères unicode sur plusieurs octets.
    \v au lieu de \n pour fin de ligne ? Déjà § est non-ASCII et sera sur 2 octets en utf-8 d'où peut-être le problème rencontré, des caractères pures utf-8 comme séparateurs ? C'est tout à fait exotique pour moi

    Un premier jet, mais le problème pour l'échappement est \ doit être au moins triplé \\\ en regexp alors qu'un autre caractère n'a pas à l'être. Mais je conserve substr_count() pour le décompte.


    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
    $sepChmp = '§'; // utf-8 car mes scripts sont en utf-8
    $dlmtTxt = '`';
    $sepLigne = "\v"; 
     
    $chaines = '`Laurent TOGIER`§`19\§ Rue Bréa`§75006§PARIS'. $sepLigne . 'Laurent TOGIER§`\§ Rue Bréa`§75006§PARIS'. $sepLigne . 'Laurent TOGIER§`19\§`§75006§PARIS'. $sepLigne . 'Laurent TOGIER§`\§`§75006§PARIS'. $sepLigne . 'Laurent TOGIER§`19\§ Rue\§ Bréa`§75006§PARIS
    '. $sepLigne . 'Laurent TOGIER§`\§\§`§75006§PARIS'. $sepLigne . '`il a dit ``aie`` § en criant`';
     
    // via preg_replace_callback() comme boucle
    $compte = 0;
    preg_replace_callback(
      // erreur "#((?<![$dlmtTxt\\\\])$dlmtTxt).*?(?1)#su", // u pour utf-8... équivalence de '#((?<!["\\\])").*?(?1)#su'
      "#((?<![$dlmtTxt\\\\])$dlmtTxt(?!$dlmtTxt)).*?(?1)#su", // équivalence de '/(?<!["\\\])"(?!").*?(?<!["\\\])"(?!")/su'
      function($match)use(&$compte, $sepChmp) {
    	  $compte += substr_count($match[0], $sepChmp);
      },
      $chaines
    );
    var_dump($compte); // 9 car j'ai ajouté il a dit ``aie`` § en criant`
     
    // via preg_match_all()
    $compte = 0;
    if( preg_match_all("#((?<![$dlmtTxt\\\\])$dlmtTxt(?!$dlmtTxt)).*?(?1)#su", $chaines, $matches) ) {
    	foreach($matches[0] as $match) $compte += substr_count($match, $sepChmp);
    }
    var_dump($compte); // 9
    EDIT: il y avait une erreur dans l'expression, correction apportée au code ci-haut. bonne chance.
    https://3v4l.org/MYt5V

  5. #5
    Membre émérite
    Avatar de badaze
    Homme Profil pro
    Chef de projets info
    Inscrit en
    Septembre 2002
    Messages
    1 412
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets info
    Secteur : Transports

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 412
    Points : 2 522
    Points
    2 522
    Par défaut
    Petit délire.

    Code php : 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
     
    <?php
    $chaines = '"Laurent TOGIER";"19\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"19\;";75006;PARIS
    Laurent TOGIER;"\;";75006;PARIS
    Laurent TOGIER;"19\; Rue\; Bréa";75006;PARIS
    Laurent TOGIER;"\;\;";75006;PARIS';
     
    $replacement = "~1_2_3_4_5_6_7_8_9_0~0_1_2_3_4_5_6_7_8_9~";
    $sepChmp     = ';';
     
    $toto        = explode(PHP_EOL,$chaines);
     
    $toto2       = str_replace("\\".$sepChmp,$replacement,$toto);
     
    $array       = array();
    foreach($toto2 as $value) {
        $array[]  = explode($sepChmp,$value);
    }
     
    foreach($array as &$value) {
        $value = str_replace($replacement,"\\".$sepChmp,$value);
    }
    var_dump($array);
    Cela ne sert à rien d'optimiser quelque chose qui ne fonctionne pas.

    Mon site : www.emmella.fr

    Je recherche le manuel de l'Olivetti Logos 80B.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    développeur web amateur
    Inscrit en
    Janvier 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : développeur web amateur
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2018
    Messages : 40
    Points : 35
    Points
    35
    Par défaut
    @ badaze,
    Bonjour, et merci pour ton "petit délire".
    Effectivement sympathique en diable, mais légèrement hors sujet. (c'est sur, je suis trop bavard, mais mon pb n'est pas descriptible en moins de 12 mots.)
    Mais merci néanmoins pour ta participation et tu peux, si tu le souhaite, revenir en deuxième semaine.

    @ Daniel,
    Au vu de ta réponse, je me dis que je n'ai pas du m'expliquer clairement puisque je n'ai pas réussi à me faire comprendre.

    Je récapitule :
    Par expérience (longue et touffue), je sais qu'on trouve de très nombreuses interprétations différentes du concept "CSV".
    Les SEULS point communs (à toutes celles qu'il m'a été donné de traiter) sont :
    1. le séparateur d'enregistrement est un caractère de contrôle (CR, LF, VT, ...) ou une composition de caractères de contrôle (CR LF par ex)
    2. le séparateur de champ est un caractère imprimable quelconque (ni espace, ni controle)
    3. le délimiteur de texte est, à priori, une des formes de guillemet possible
    4. le délimiteur de texte présent à l'intérieur d'un champ texte est doublé
    5. il est possible d'échapper un séparateur présent dans un champ texte délimité en le faisant précédé par un caractère d'échappement, qui est la plupart du temps l'antislash (mais malheureusement pas toujours)


    J'ai déjà programmé la détection des deux séparateurs et du délimiteur (ce qui me permet en même temps de détecter les fichiers "hétérogènes", résultats de fusions sauvages de fichiers d'origines diverses ...)
    Il ne me manque plus que la détection d'un éventuel caractère d'échappement.
    A ce point de recherche, je connais déjà les deux séparateurs et le délimiteur.
    Il me suffit donc de trouver DANS LES CHAMPS TEXTE DELIMITÉS les occurrences des séparateurs et d'analyser la stat du caractère les précédant résultante.

    DONC je ne cherche pas à compter les antislash (un simple substr_count ferait la blague) mais à trouver tous les caractères répondant à ces deux critères :
    1. se trouvant entre une paire de délimiteur de texte
    2. immédiatement suivi par un séparateur de champ (ou un séparateur d'enregistrement si pas trop compliqué, mais je peux faire deux stats)


    SI un caractère d'échappement est utilisé et SI des délimiteur sont présents dans des champs texte, je devrais avoir un gagnant dont le code ascii aura été vu beaucoup plus souvent que les autres, s'il n'est pas seul ...
    Comme indiqué dans mon post d'origine, je trouve sans difficulté la première ou la dernière occurrence d'un séparateur de champ précédé de son (éventuel) caractère d'échappement (ce que j'appelle le doublet) et ma regex
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $rgxEsc =  "/$dlmtTxt.*?([^$dlmtTxt])$sepChmp.*?$dlmtTxt/";
    preg_match_all($rgxEsc, $chaines, $m);
    me rends tous les "éventuels caractères d'échappement" (première occurence) dans $m[1].

    MAIS ma regex commençant et finissant par le délimiteur de champ, la recherche continue ensuite à partir, non pas de ce qui suit l'occurrence du doublet visé, mais après le full match (cad la fin du texte délimité).
    Ce point m'empêche de capturer tous les doublets répétés (2me et suivants) à l'intérieur d'un même champ texte.

    Je n'arrive pas à trouver l'astuce d'expression régulière qui forcerait la suite de la recherche à partir du doublet trouvé plutôt qu'après le full match.

    As-tu une idée pour ce faire ?
    Existe-t-il un solution pour faire la recherche répétitive d'une pattern à l'intérieur de chacun des résultats de la recherche répétitive d'une autre pattern ? (sans boucle php, le but est d'être rapide (qd on teste 300k enregistrements, c'est critique))

    Merci par avance de ton attention.

  7. #7
    Membre habitué Avatar de daniel61
    Inscrit en
    Décembre 2006
    Messages
    139
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 139
    Points : 169
    Points
    169
    Par défaut
    Salut, en effet j'avais jamais capté que le sujet était une auto-détection du caractère d'échappement: désolé. \G en PHP a les ailles coupées, dans un autre langage il est peut-être possible en 1 regexp via \G... mais arriver en 1 regexp en PHP avec un \G handicapé relèverait d'une gymnastique intellectuelle peu compatible avec la maintenance du code, mais ce n'est que mon humble avis. Je suggère de procéder en 2 phases, d'abord extraire toutes les sous chaines encadrées et de chacune de ces sous chaines encadrées en extraire le caractère précédent $sepChmp pour en compter les occurrences. Mais restera le problème des CSV qui utilisent le caractère d'échappement sur les formes de guillemets au lieu de le doubler ou qui n'utilise pas l'échappement sur le séparateur dans une sous chaîne encadrée.

    https://3v4l.org/4jInS

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    <pre><?php
     
    function escape_possible($chaines, $sepChmp, $dlmtTxt) {
    	$escape_possible = [];
    	if( preg_match_all("#((?<![$dlmtTxt])$dlmtTxt(?!$dlmtTxt)).*?(?1)#su", $chaines, $encadres) ) {
    		foreach( $encadres[0] as $encadre) {
    			if( preg_match_all("#.(?=$sepChmp)#su", $encadre, $escapes) ) {
    				foreach($escapes[0] as $escape) {
    					if(isset($escape_possible[$escape])) $escape_possible[$escape]++;
    					else $escape_possible[$escape] = 1;
    				}
    			}
    		}
    	}
    	arsort($escape_possible);
    	return $escape_possible;
    }
     
    // cas 1
    $sepChmp = ';';
    $dlmtTxt = '"';
    $chaines = '"il a dit ""aie"" ; en criant"
    "Laurent TOGIER";"19\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"19\;";75006;PARIS
    Laurent TOGIER;"\;";75006;PARIS
    Laurent TOGIER;"19\; Rue\; Bréa";75006;PARIS
    Laurent TOGIER;"\;\;";75006;PARIS';
    var_dump(escape_possible($chaines, $sepChmp, $dlmtTxt));
    /*
    array(2) {
      ["\"]=>
      int(8)
      [" "]=>
      int(1)
    }
    */
     
     
    // cas 2
    $sepChmp = '§'; // utf-8
    $dlmtTxt = '`';
    $chaines = '`Laurent TOGIER`§`19/§ Rue Bréa`§75006§PARIS
    Laurent TOGIER§`/§ Rue Bréa`§75006§PARIS
    Laurent TOGIER§`19/§`§75006§PARIS
    Laurent TOGIER§`/§`§75006§PARIS
    Laurent TOGIER§`19/§ Rue/§ Bréa`§75006§PARIS
    Laurent TOGIER§`/§/§`§75006§PARIS
    `il a dit ``aie`` § en criant`';
    var_dump(escape_possible($chaines, $sepChmp, $dlmtTxt));
    /*
    array(2) {
      ["/"]=>
      int(8)
      [" "]=>
      int(1)
    }
    */

  8. #8
    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
    En une pattern:
    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
    $pattern = '~
      # Soit la position contiguë au dernier match, soit le " ouvrant
      (?: \G (?!\A) | " ;* )
     
      # Pour être sûr de ne pas sortir des guillemets
      [^;"]* (?: "" [^;"]* )* 
     
      # Ensuite deux possibilités:
      (?: # le " de fin, dans ce cas on avance au prochain " (ou à la fin de la chaîne)
          " (?: [^"]* (?: " | \z ) )
        | # ou le séparateur de champs, dont on capture le caractère précédent dans un lookbehind) 
          (?<=(.)) ;
      )
    ~xu';
     
    $subject = '"il a dit ""aie"" ; en criant"
    "Laurent TOGIER";"19\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"\; Rue Bréa";75006;PARIS
    Laurent TOGIER;"19\;";75006;PARIS
    Laurent TOGIER;"\;";75006;PARIS
    Laurent TOGIER;"19\; Rue\; Bréa";75006;PARIS
    Laurent TOGIER;"\;\;";75006;PARIS';
     
    if ( preg_match_all($pattern, $subject, $matches) ) {
        $found = count_chars(implode('', $matches[1]), 1);
        $found = array_combine(array_map('chr', array_keys($found)), $found);
     
        print_r($found);
    }
    Pour tester avec des délimiteurs et des caractères de protection différents:
    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
    34
    35
    $formatted = [];
     
    $formatted['subject'] = '%1$sil a dit %1$s%1$saie%1$s%1$s %2$s en criant%1$s
    %1$sLaurent TOGIER%1$s%2$s%1$s19\%2$s Rue Bréa%1$s%2$s75006%2$sPARIS
    Laurent TOGIER%2$s%1$s\%2$s Rue Bréa%1$s%2$s75006%2$sPARIS
    Laurent TOGIER%2$s%1$s19\%2$s%1$s%2$s75006%2$sPARIS
    Laurent TOGIER%2$s%1$s\%2$s%1$s%2$s75006%2$sPARIS
    Laurent TOGIER%2$s%1$s19\%2$s Rue\%2$s Bréa%1$s%2$s75006%2$sPARIS
    Laurent TOGIER%2$s%1$s\%2$s\%2$s%1$s%2$s75006%2$sPARIS';
     
    $formatted['pattern'] = '~
      # Soit la position contiguë au dernier match, soit le %1$s ouvrant
      (?: \G (?!\A) | %1$s %2$s* )
     
      # Pour être sûr de ne pas sortir des guillemets
      [^%2$s%1$s]* (?: %1$s%1$s [^%2$s%1$s]* )* 
     
      # Ensuite deux possibilités:
      (?: # le %1$s de fin, dans ce cas on avance au prochain %1$s (ou à la fin de la chaîne)
          %1$s (?: [^%1$s]* (?: %1$s | \z ) )
        | # ou le séparateur de champs, dont on capture le caractère précédent dans un lookbehind) 
          (?<=(.)) %2$s
      )
    ~xu';
     
    $placeholders = [ '"', ';' ];
    $pattern = vsprintf($formatted['pattern'], $placeholders);
    vsprintf($formatted['subject'], $placeholders);
     
    if ( preg_match_all($pattern, $subject, $matches) ) {
        $found = count_chars(implode('', $matches[1]), 1);
        $found = array_combine(array_map('chr', array_keys($found)), $found);
     
        print_r($found);
    }
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    développeur web amateur
    Inscrit en
    Janvier 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : développeur web amateur
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2018
    Messages : 40
    Points : 35
    Points
    35
    Par défaut
    @ Daniel,
    Bien reçu ton dernier post proposant une boucle php.
    J'avais testé cette solution (presque complète, comme tu le soulignes) mais cela se fait attendre sur des gros fichiers.
    Merci beaucoup pour tes efforts.
    La proposition de CosmoKnaki me semble plus proche de la solution que j'imaginais.

    En quoi \G a-t-il "les ailes coupées" en PHP ? je ne trouve rien à ce sujet et la solution de CosmoKnaki, qui l'utilise, fonctionne parfaitement sur mon pc et sur eval.org ?



    @ CosmoKnaki
    Waow !
    de la différence entre l'amateur que je suis et un Maître en regex.
    J'ai commencé à étudier ta regex et il m'apparait évident que je vais devoir verser quelques euros à O'Reilly, ce que j'aurais sans doute du faire depuis longtemps.
    Farouche adversaire de la méthode "singe voit, singe fait", je préfère comprendre ce que je code. Je vais donc creuser plus profond et passer mon we là-dessus.
    Merci infiniment de m'avoir montré la voie.

    : proverbe chinois : "plus près de la lumière, tu es éclairé."
    : une relation entre "CosmoKnaki" et "Les cochons dans l'espace" ?
    : Quel est le volume du bocal ?


    loup maigre

  10. #10
    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
    En quoi \G a-t-il "les ailes coupées" en PHP ?
    Je pense que daniel61 fait référence à la différence de comportement entre les regex perl et les regex pcre. Dans les deux cas \G réussi lorsque la position précédente a été atteinte, la différence, c'est qu'avec Perl le caractère de la position précédente doit être consommé par le match précédent, alors qu'avec PHP non. Exemples:

    je vais devoir verser quelques euros à O'Reilly
    Les anciennes éditions de Mastering regular expressions sont trouvables gratuitement. L'essentiel est de bien comprendre les quantificateurs et le backtracking, le reste c'est du gadget.

    une relation entre "CosmoKnaki" et "Les cochons dans l'espace" ?
    Aucun lien avec les cochons dans l'espace (ni les vétérinaires à l'hôpital d'ailleurs).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    développeur web amateur
    Inscrit en
    Janvier 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : développeur web amateur
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2018
    Messages : 40
    Points : 35
    Points
    35
    Par défaut
    @CosmoKnaki

    Bien reçu, merci.
    Bonne continuation
    Roland

Discussions similaires

  1. Compter le nombre d'occurence dans une chaine
    Par shirya dans le forum Langage
    Réponses: 2
    Dernier message: 16/10/2007, 20h39
  2. Réponses: 4
    Dernier message: 19/09/2006, 10h30
  3. Réponses: 2
    Dernier message: 14/09/2006, 22h00
  4. Réponses: 4
    Dernier message: 09/09/2006, 10h18
  5. Position d'une occurence dans une chaine
    Par Maglight dans le forum Langage
    Réponses: 3
    Dernier message: 04/07/2005, 10h08

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