[RESOLU] string avec virgules et parenthèse en array

Eléphanteau du PHP | 20 Messages

05 juin 2019, 12:29

Bonjour
existe t'il une méthode élégante de convertir une chaine de caractère ressemblant à ça :

Code : Tout sélectionner

"(a,b,(c,d),((e,f),g),h)"
en un tableau ressemblant à ça :

Code : Tout sélectionner

Array ( [0] => a [1] => b [2] => Array ( [0] => c [1] => d ) [3] => Array ( [0] => Array ( [0] => e [1] => f ) [1] => g ) [4] => h )
sachant que je n'ai aucune idée du nombre d'imbrication de parenthèse ?

Avatar du membre
Mammouth du PHP | 1609 Messages

05 juin 2019, 14:09

Je ne sais pas si c'est élégant mais voici une solution toute bête en exploitant la fonction json_decode de php. A voir si tu veux mettre des éléments un peu plus complexes dans ta chaîne que des simples lettres.
$string = "(a,b,(c,d),((e,f),g),h)";
echo "string = $string<br/>";

function stringToArray($string) {
  $string = str_replace(array('(', ')'), array('[', ']'), $string);
  $string = preg_replace('`(\w+)`', '"$1"', $string);

  return json_decode($string);
}

echo '<pre>';
print_r(stringToArray($string));
echo '</pre>';

Sortie :
string = (a,b,(c,d),((e,f),g),h)

Array
(
    [0] => a
    [1] => b
    [2] => Array
        (
            [0] => c
            [1] => d
        )

    [3] => Array
        (
            [0] => Array
                (
                    [0] => e
                    [1] => f
                )

            [1] => g
        )

    [4] => h
)
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 20 Messages

06 juin 2019, 10:15

Effectivement, pour exemple simple, ça marche ... mais en situation réel, j'ai plutôt des truc qui resemble à ça :

Code : Tout sélectionner

string = "('1xrWb_VEHEZRY9JJ9v3lYY',#41,'Default',$,$,#619,$,$,.ELEMENT.,(44,59,59,999999),(4,59,59,999999),150000.,$,$)"
et là, ta fonction ne retourne rien :(

Apparemment, les simple cote, les dièses et les points pose problème ...

Avatar du membre
Mammouth du PHP | 1609 Messages

06 juin 2019, 10:28

Oui dans ce cas faut adapter l'expression régulière qui n'était faite que pour capturer des mots. En prenant tout sauf virgules et crochets :
$string = "('1xrWb_VEHEZRY9JJ9v3lYY',#41,'Default',$,$,#619,$,$,.ELEMENT.,(44,59,59,999999),(4,59,59,999999),150000.,$,$)";
echo "string = $string<br/>";

function stringToArray($string) {
  $string = str_replace(array('(', ')'), array('[', ']'), $string);
  $string = preg_replace('`([^,\[\]]+)`', '"$1"', $string);

  return json_decode($string);
}

echo '<pre>';
print_r(stringToArray($string));
echo '</pre>';

Sortie :
string = ('1xrWb_VEHEZRY9JJ9v3lYY',#41,'Default',$,$,#619,$,$,.ELEMENT.,(44,59,59,999999),(4,59,59,999999),150000.,$,$)

Array
(
    [0] => '1xrWb_VEHEZRY9JJ9v3lYY'
    [1] => #41
    [2] => 'Default'
    [3] => $
    [4] => $
    [5] => #619
    [6] => $
    [7] => $
    [8] => .ELEMENT.
    [9] => Array
        (
            [0] => 44
            [1] => 59
            [2] => 59
            [3] => 999999
        )

    [10] => Array
        (
            [0] => 4
            [1] => 59
            [2] => 59
            [3] => 999999
        )

    [11] => 150000.
    [12] => $
    [13] => $
)
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 20 Messages

06 juin 2019, 10:37

Génial !!!
Merci à toi Saian :-)

Eléphanteau du PHP | 20 Messages

06 juin 2019, 12:23

Question limite or sujet : comment fait on l'opération inverse ?
(se sent que je vais rapidement avoir besoin de ça)

Avatar du membre
Mammouth du PHP | 1609 Messages

06 juin 2019, 12:43

Comme ça : :wink:
function arrayToString($array)
{
  $string = json_encode($array);
  $string = str_replace(array('[', ']', '"'), array('(', ')', ''), $string);

  return $string;
}
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 20 Messages

06 juin 2019, 13:52

Royal !
encore merci ==> RESOLU

Eléphanteau du PHP | 20 Messages

13 juin 2019, 15:20

Arf ... ya un problème quand un élément chaine de caractère (entre simple cote) contient des parenthèse, genre ça :

Code : Tout sélectionner

(a,'chaine avec (parenthèse) dedans',(c,d),((e,f),g),h)
Comment, par exemple, les remplacer momentanément mais sans remplacer les autres parenthèses qui définissent les ensemble ?

Avatar du membre
Mammouth du PHP | 1609 Messages

13 juin 2019, 15:55

Forcément ça complique un peu les choses... avec ça, ça supportera également les crochets ^^
function stringToArray($string) {
  /* escape some chars */
  $string = str_replace(array('[', ']'), array(':ob:', ':cb:'), $string);
  $string = preg_replace_callback("`'(.*?)'`", function ($matches) {
      return "'".str_replace(array('(', ')'), array(':op:', ':cp:'), $matches[1])."'";
    }, $string);
  
  /* jsonify string */
  $string = preg_replace('`([^,\(\)]+)`', '"$1"', $string);
  $string = str_replace(array('(', ')'), array('[', ']'), $string);

  $array = json_decode($string);
  return restoreEscaped($array);
}
function restoreEscaped($array)
{
  return array_map(function ($entry) {
    return is_array($entry)
      ? restoreEscaped($entry)
      : str_replace(
          array(':ob:', ':cb:', ':op:', ':cp:'),
          array('[', ']', '(', ')'),
          $entry);
    }, $array);
}

function arrayToString($array)
{
  $array = escapeBrackets($array);
  $string = json_encode($array);
  $string = str_replace(array('[', ']', '"', ':ob:', ':cb:'), array('(', ')', '', '[', ']'), $string);

  return $string;
}
function escapeBrackets($array) {
  return array_map(function ($entry) {
    return is_array($entry)
      ? escapeBrackets($entry)
      : str_replace(
          array('[', ']'),
          array(':ob:', ':cb:'),
          $entry);
  }, $array);
}
Modifié en dernier par Saian le 13 juin 2019, 17:09, modifié 1 fois.
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 20 Messages

13 juin 2019, 16:44

J'était en train de me battre avec ça :

Code : Tout sélectionner

function param2tab($ifcParam){ // mise en tableau des parametres $ifcParam=preg_replace("#('.*)\((.*')#","$1&#40;$3",$ifcParam); $ifcParam=preg_replace("#('.*)\)(.*')#","#$1&#41;$3#",$ifcParam); $string = str_replace(array('(', ')'), array('[', ']'), $ifcParam); $string = preg_replace('`([^,\[\]]+)`', '"$1"', $string); return json_decode($string); }
J'étais loin du compte !
(j’analyse tout ça demain)
encore merci.

Avatar du membre
Mammouth du PHP | 1609 Messages

13 juin 2019, 17:05

Le faire avec une ou deux expressions régulières me paraissait trop compliqué. C'est pour ça que j'ai plutôt fait une expression régulière simple pour récupérer toutes les chaînes entre apostrophes et y appliquer une fonction de rappel avec preg_match_callback pour pouvoir remplacer les parenthèses avec un simple str_replace. Mon parti pris a été de remplacer les caractères gênants par des chaînes arbitraires (mais signifiantes) qui à priori ne devraient pas être présentes dans la chaîne originale, puis de restaurer ces chaînes de remplacement par leur caractère original à la fin du traitement.

Je t'ai mis le stringToArray et le arrayToString. ;)
Développeur web depuis + de 20 ans

Eléphanteau du PHP | 20 Messages

14 juin 2019, 10:38

Bon ... ben j'ai plus qu'à comprendre tout ça (et doubler la poids du code avec des commentaires que je puisse encore comprendre dans 6 mois O:) )
Encore merci. :wink:

Eléphanteau du PHP | 20 Messages

14 juin 2019, 10:59

Ca à l'air de fonctioner mais j'ai des message malpolis :

Code : Tout sélectionner

Warning: array_map(): Argument #2 should be an array in B:\WWW\ifc_position\res\fonctions.php on line 34
Ca vise l'avant dernière ligne de la fonction "restoreEscaped" :

Code : Tout sélectionner

26|function restoreEscaped($array){ | ... 34| }, $array); 35|}

Eléphanteau du PHP | 20 Messages

14 juin 2019, 11:02

J'ai rajouté un truc qui semble filter :

Code : Tout sélectionner

function restoreEscaped($array){ //https://forum.phpfrance.com/post460425.html if(is_array($array)) return array_map(function ($entry) { return is_array($entry) ? restoreEscaped($entry) : str_replace( array(':ob:', ':cb:', ':op:', ':cp:'), array('[', ']', '(', ')'), $entry); }, $array); }