substr, explode, sscanf et des expressions régulières !
Dans le challenge DBZ_2, il faut parser ce type de chaîne de caractères :
RNBOAPHELSK-182
Pour en sortir 2 informations :
Il faut donc parser la chaîne de caractères pour récupérer ces 2 valeurs. Passage en revue de plusieurs techniques de parsing.
Pour les exemples ci-dessous, on considère que RNBOAPHELSK-182 est stocké dans $object.
Cette fonction permet de récupérer la portion d’une chaîne de caractères.
Dans ce cas précis, pour récupérer le code, il faut que je connaisse la longueur de celui-ci. Une possibilité est de déterminer la position du tiret « – » dans la chaîne principale.
$position = strpos($object, '-');
$code = substr($object, 0, $position);
// Et donc :
$weight = substr($object, $position + 1, 3);
Le code ci-dessus peut être optimisé :
$code = substr($object,
0,
strpos($object, '-')
);
$weight = substr($object, -3);
Je n’ai finalement plus besoin de $position et je passe donc strpos dans l’appel à substr.
Pour récupérer la fin d’une chaîne de caractères, je peux utiliser une valeur négative. Ici je récupère donc les 3 derniers caractères de $object.
La doc complète : substr.
Cette fonction permet de découper une chaine de caractères, selon un séparateur. Ce séparateur peut être 1 seul caractère ou 1 chaine de caractères plus longue.
Ici, le tiret est le séparateur.
$informationss = explode('-', $object);
$code = $informations[0];
$weight = $informations[1];
explode retourne un tableau avec les différentes portions de la chaîne de caractères principale. Ici il y a 1 seul tiret, donc 2 portions, une avant (0, le code), une après (1, le poids). Le code ci-dessus peut être optimisé avec une double affectation :
[$code, $weight] = explode('-', $object);
La doc complète : explode.
Cette fonction est « l’inverse » de la fonction sprintf.
sprintf permet d’intégrer les valeurs de variables dans une chaine de caractères, à la manière d’un publipostage.
$fruit = 'pomme';
echo sprintf('Je mange une %s', $fruit);
// Affiche : Je mange une pomme
s représente une chaîne de caractères.
sscanf va donc se comporter à l’inverse. C’est-à-dire que l’on va pouvoir définir le format d’une chaîne et en récupérer les différentes valeurs. Le problème avec notre challenge, c’est que scan utilise les espaces comme séparateur. Ce qui veut dire que ce code ne fonctionne pas comme souhaité :
[$code, $vert] = sscanf($object, '%s-%d');
Il n’y a pas d’espace, donc $code va récupérer toute la chaîne, et il n’y aura rien dans $weight.
On peut donc remplacer le tiret pour commencer :
$object = str_replace('-', ' ', $object);
[$code, $weight] = sscanf($object, '%s %d');
Cette fois-ci ça fonctionne 🙂
La doc complète : sscanf et sprintf.
Ah ces bonnes vieilles regex ! Analysons $object, il contient :
On peut donc écrire ces 2 récupérations, par des expressions régulières :
preg_match('/[A-Z]+/', $object, $code);
$code = $code[0];
preg_match('/[0-9]{3}/', $object, $weight);
$weight = $weight[0];
Attention au fonctionnement de cette fonction, elle retourne le nombre de correspondances trouvées dans la chaîne de caractères principale. Et les correspondances sont assignées par référence, dans un tableau. Ici je sais que je ne vais avoir qu’une seule correspondance. Je récupère donc la valeur souhaitée avec [0].
La doc complète : preg_match
2 utilitaires pour rédiger ou tester des regex : phpliveregex et regex101.
Revenons au challenge !
Je choisis d’utiliser ici explode.
$total = 0;
foreach ($objects as $object) {
[$code, $weight] = explode('-', $object);
$codeMini = substr($code, 0, 2) . substr($code, -2) . '-' . floor($weight / 10);
if (in_array($codeMini, $capsules)) {
$total += $weight;
}
}
J’initialise $total à 0, puisque je cherche une somme.
Je parcours tous mes objects (attention, le challenge fournit une clé « objets » et non « objects », mais on va corriger ça :p )
J’utilise donc explode pour extraire le code et le poids.
Je définis le codeMini. J’utilise ici substr puisque ce sont bien des portions de $code que je cherche. J’utilise d’ailleurs « -2 » pour les 2 derniers caractères.
Si $codeMini est dans $capsules, j’incrémente $total avec $weight.
$total = 0;
foreach ($objects as $object) {
$total += (in_array(
substr(explode('-', $object)[0], 0, 2) .
substr(explode('-', $object)[0], -2) . '-' .
floor(explode('-', $object)[1] / 10)
, $capsules)
) ? explode('-', $object)[1] : 0;
}
On remplace le if par un ternaire. Soit j’ajoute le poids, soit j’ajoute zéro.
Et je récupère à la volée les résultats de explode. Ici c’est pour le fun puisque mon explode est utilisé plusieurs fois, j’ai plutot intérêt à stocker le résultat. Mais cette syntaxe est possible.
Voici 3 challenges qui démarrent avec des données à parser :
Corrigés, challenges, actualités, veille technique... aucun spam.