Page 1 sur 2

Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 17:46
par roseline
Bonjour,

Cela fait quelques jours que je cherche des infos, mais là je sèche :-(
J'espère que quelqu'un aura une solution ;-)

Mon problème est le suivant:
Je dois exporter des données dans un fichier txt = j'y arrive.
Mais je dois "manipuler" un champ comme suit
- dans la table, j'ai un champ qui comprend une valeur, p.ex. 100.00 ou 20.50
- dans le fichier txt, il doit apparaître 1) sans le point 2) sur une longueur fixe de 9 caractères; ce qui devrait me donner
000010000
ou
000002050

Je pense que je dois utiliser des string et des array, mais je n'y arrive pas :-(

Voici ci-dessous mon code qui me génère bien le fichier txt mais avec 20.50 au lieu de 000002050...

Merci d'avance pour votre aide!

<?php
$UserID = $_GET['UserID'];
?>
<?php
include "config.inc.php";

// la variable qui va contenir les données CSV
$outputCsv = '';

///////////////////////// VALEURS Society ET SiteCode A CHANGER ////////////////////////////////////
$requete = "SELECT CheckID, CheckValor, StatutID, CustomerNumber, Society, SiteCode, SiteCountry FROM base WHERE StatutID = 'U' AND Society = '1' AND SiteCode = '000' AND SiteCountry = 'CH'";
$sql = mysql_query($requete);
if(mysql_num_rows($sql) > 0)
{
$i = 0;

while($Row = mysql_fetch_assoc($sql))
{
$i++;

// On parcours $Row et on ajout chaque valeur à cette ligne
foreach($Row as $clef => $valeur)
$outputCsv .= trim($valeur).'';

// Suppression du ; qui traine à la fin
$outputCsv = rtrim($outputCsv, '');

// Saut de ligne
$outputCsv .= "\n";

}

}
else
exit('');

/// DONNEES
$Date= date("Y-m-j H:i:s");

/// Ecriture du fichier
header("Content-disposition: attachment; filename=\"ACH0001".date("YmdHis").".txt\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/vnd.ms-excel\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");

echo $outputCsv;
exit();
?>

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 18:37
par sirakawa
<?PHP
$val = 23.50;
$str_val = number_format ( $val , 0 , '' , '' );
//$str_val = "$val";
$str_val = str_pad ($str_val, 9, "0",STR_PAD_LEFT);
print"$str_val";
?>
Pour les explications, consulter le manuel.
On doit pouvoir aussi passer par:
$str_val = "$val";
str_replace(.....);
str_pad comme ci-dessus;

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 19:11
par Calimero
Mais je dois "manipuler" un champ comme suit
- dans la table, j'ai un champ qui comprend une valeur, p.ex. 100.00 ou 20.50
- dans le fichier txt, il doit apparaître 1) sans le point 2) sur une longueur fixe de 9 caractères; ce qui devrait me donner
000010000
ou
000002050
Une autre solution, courte, en deux parties :

La disparition du point correspond à une multiplication par 100.
L'alignement sur 9 chiffres (avec les zéros non-significatifs) peut se faire avec la fonction sprintf et le bon code de formatage (u pour un entier non-signé, 09 pour le remplissage par des zéros sur 9 caractères à gauche)

ce qui donne :
<?php
$num = 23.50;
echo sprintf('%09u',$num*100); // affiche 000002350
Et voilà le travail :)

@+

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 19:33
par roseline
Whaow, dit comme ça, c'est vrai que ça à l'air tellement facile!

Super cool, merci, je vais tester cela demain :-)

Bonne soirée

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 20:25
par sirakawa
Et que produit cette méthode dédiée à un cas particulier si, par hasard on tombe sur un nombre à trois décimales? ou à une seule décimale, parce qu'on a négligé le 0 final de 12.50 qu'on a écrit 12.5?

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 21:42
par Calimero
Et que produit cette méthode dédiée à un cas particulier si, par hasard on tombe sur un nombre à trois décimales?
Dans ce cas la multiplication par 100 ne fonctionnerait plus, en effet, et il faudrait éliminer le point par un autre moyen. Mais j'ai pensé que le cas était improbable vu le 100.00 donné dans le post initial :) (format monétaire)
ou à une seule décimale, parce qu'on a négligé le 0 final de 12.50 qu'on a écrit 12.5?
Mathématiquement parlant, les deux nombres sont identiques (les zéros à droite après la virgule sont non-significatifs), donc la multiplication par 100 donnera rigoureusement le même résultat, ce tu peux d'ailleurs vérifier avec php :
$num=426.3;
echo sprintf('%09u',$num*100); // 000042630

Re: Problème conversion champ en longueur fixe

Posté : 09 mars 2012, 22:44
par sirakawa
C'est pour cette raison qu'il faudrait donner, en toute circonsance, la préférence à une méthode qui résolve le cas général, même si le problème au départ est un cas particulier. Rien ne dit que l'évolution ne créera pas un cas particulier non prévu.
On s'éviterait de devoir après coup ajouter une profusion de lignes de code pour éliminer les cas qu'on n'avait pas prévus...
Celui, par exemple, qui a écrit la fonction d'inversion d'une matrice 2X2 devrait chercher si par hasard il n'existait pas des matrices aures que 2X2 et une méthode générale d'inversion des matrices carrées.

Re: Problème conversion champ en longueur fixe

Posté : 10 mars 2012, 03:24
par Calimero
C'est pour cette raison qu'il faudrait donner, en toute circonsance, la préférence à une méthode qui résolve le cas général, même si le problème au départ est un cas particulier. Rien ne dit que l'évolution ne créera pas un cas particulier non prévu.
On s'éviterait de devoir après coup ajouter une profusion de lignes de code pour éliminer les cas qu'on n'avait pas prévus...
Oui, ton code est plus générique et bullet-proof que le mien. Le mien a, en revanche, l'avantage de la concision et de la maintenabilité, qui peuvent aussi être des paramètres pertinents (et sur ce dernier point, je n'ai jamais été vraiment content des codes que j'ai pu produire qui utilisaient str_pad(), c'est pourquoi je proposais ici une approche alternative employant sprintf() qui peut parfois jouer le même rôle avantageusement, si on prend toutefois le temps d'en découvrir la syntaxe).

Pour ce qui est de la multiplication, j'avoue volontiers une petite prise de risque que tu as bien relevée, mais éclairée par mon expérience personnelle et une lecture attentive du post initial (100.00 + traitement fichiers texte). Le mieux est parfois l'ennemi du bien, comme on dit :)

Re: Problème conversion champ en longueur fixe

Posté : 10 mars 2012, 17:03
par roseline
Ok, je comprend bien la raison des deux propositions que vous me donner :-)
Perso, en effet, la solution "simple" me suffit.

Par contre, je n'arrive pas à l'intégrer à mon script :-(
J'ai vu qu'il fallait que je change mysql_fetch_assoc en mysql_fetch_array si je veux travailler sur un champ.
Est-ce bien juste?

Voici mon script corrigé; mais du coup, je n'ai plus de fichier txt qui se génère :-(
Merci encore pour votre aide!

<?php
$UserID = $_GET['UserID'];
?>
<?php
include "config.inc.php";

// la variable qui va contenir les données CSV
$outputCsv = '';

///////////////////////// VALEURS Society ET SiteCode A CHANGER ////////////////////////////////////
$requete = "SELECT CheckID, CheckValor, StatutID, CustomerNumber, Society, SiteCode, SiteCountry FROM base WHERE StatutID = 'U' AND Society = '1' AND SiteCode = '000' AND SiteCountry = 'CH'";
$sql = mysql_query($requete) or die(mysql_error());
if(mysql_num_rows($sql) > 0)
{
$i = 0;

while($row = mysql_fetch_array($sql))
$CheckID = $row['CheckID'];
//// travail sur la valeur du chèque
$val = $row['CheckValor'];
$valeurcheque = sprintf('%09u', $val*100);
//// fin travail
$StatutID = $row['StatutID'];
$CustomerNumber = $row['CustomerNumber'];
$Society = $row['Society'];
$SiteCode = $row['SiteCode'];
$SiteCountry = $row['SiteCountry'];

$valeur = ($CheckID, $valeurcheque, $StatutID, $CustomerNumber, $Society, $SiteCode, $SiteCountry);

{
$i++;

// On parcours $Row et on ajout chaque valeur à cette ligne
foreach($row)
$outputCsv .= trim($valeur).'';

// Suppression du ; qui traine à la fin
$outputCsv = rtrim($outputCsv, '');

// Saut de ligne
$outputCsv .= "\n";

}

}
else
exit('');

/// DONNEES
$Date= date("Y-m-j H:i:s");


/// Ecriture du fichier
header("Content-disposition: attachment; filename=\"ACH0001".date("YmdHis").".txt\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/vnd.ms-excel\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");

echo $outputCsv;
exit();
?>

Re: Problème conversion champ en longueur fixe

Posté : 11 mars 2012, 00:12
par Calimero
@roseline : tu as entré ton nouveau code entre le while(...) et l'accolade ouvrante {. Ceci expliquant cela.

Re: Problème conversion champ en longueur fixe

Posté : 11 mars 2012, 14:29
par roseline
:-( Ben oui, bien sûr!

Par contre, j'essaye de le mettre à différents endroits, et le fichier ne se génère toujours pas :-(
J'ai essayé après le $i = 0;
Après le $i++;

J'en suis là.....

<?php
$UserID = $_GET['UserID'];
?>
<?php
include "config.inc.php";

// la variable qui va contenir les données CSV
$outputCsv = '';

///////////////////////// VALEURS Society ET SiteCode A CHANGER ////////////////////////////////////
$requete = "SELECT CheckID, CheckValor, StatutID, CustomerNumber, Society, SiteCode, SiteCountry FROM base WHERE StatutID = 'U' AND Society = '1' AND SiteCode = '000' AND SiteCountry = 'CH'";
$sql = mysql_query($requete) or die(mysql_error());
if(mysql_num_rows($sql) > 0)
{
$i = 0;

while($row = mysql_fetch_array($sql))
{

$i++;

// On parcours $Row et on ajout chaque valeur à cette ligne
foreach($row)
$CheckID = $row['CheckID'];
//// travail sur la valeur du chèque
$val = $row['CheckValor'];
$valeurcheque = sprintf('%09u', $val*100);
//// fin travail
$StatutID = $row['StatutID'];
$CustomerNumber = $row['CustomerNumber'];
$Society = $row['Society'];
$SiteCode = $row['SiteCode'];
$SiteCountry = $row['SiteCountry'];

$valeur = ($CheckID, $valeurcheque, $StatutID, $CustomerNumber, $Society, $SiteCode, $SiteCountry);

$outputCsv .= trim($valeur).'';

// Suppression du ; qui traine à la fin
$outputCsv = rtrim($outputCsv, '');

// Saut de ligne
$outputCsv .= "\n";

}

}
else
exit('');

/// DONNEES
$Date= date("Y-m-j H:i:s");


/// Ecriture du fichier
header("Content-disposition: attachment; filename=\"ACH0001".date("YmdHis").".txt\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/vnd.ms-excel\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");

echo $outputCsv;
exit();
?>

Re: Problème conversion champ en longueur fixe

Posté : 12 mars 2012, 13:28
par Calimero
L'instruction foreach() n'a rien à faire là-dedans, tu te situes déjà dans un while.

N'hésite pas à repartir du code initial si besoin et de comparer les structures. Tu as fait beaucoup de modifications (certaines hasardeuses) qui expliquent certainement ton problème.

Re: Problème conversion champ en longueur fixe

Posté : 12 mars 2012, 18:14
par roseline
Oui, je vais reprendre tranquillement le tout depuis le début....
Merci :-)

Re: Problème conversion champ en longueur fixe

Posté : 12 mars 2012, 19:06
par roseline
Hi hi, cela fait du bien de repartir à zéro!

Voici le code qui fonctionne comme je le souhaite :-)
... et j'ai même réussi à mettre un sprintf supplémentaire.

Pour ceux qui souhaite:
La base de l'export est
880700000008783020.0012341001CH
880700000056547010.005486859791001CH
Le résultat est
8807000000087830000002000U00000012341001CH
8807000000565470000001000U05486859791001CH

<?php
include "config.inc.php";

// la variable qui va contenir les données CSV
$outputCsv = '';

///////////////////////// VALEURS Society ET SiteCode A CHANGER ////////////////////////////////////
$requete = "SELECT CheckID, CheckValor, StatutID, CustomerNumber, Society, SiteCode, SiteCountry FROM base WHERE StatutID = 'U' AND Society = '1' AND SiteCode = '000' AND SiteCountry = 'CH'";
$sql = mysql_query($requete);
if(mysql_num_rows($sql) > 0)
{
$i = 0;

while($Row = mysql_fetch_array($sql))
{
$i++;

$ID = $Row[CheckID];
$val = sprintf('%09u',$Row[CheckValor]*100);
$statut = $Row[StatutID];
$cnumber = sprintf('%010u',$Row[CustomerNumber]);
$soc = $Row[Society];
$code = $Row[SiteCode];
$country = $Row[SiteCountry];

$outputCsv .= "$ID$val$statut$cnumber$soc$code$country\n";

}

}
else
exit('');

/// DONNEES
$Date= date("Y-m-j H:i:s");


/// Ecriture du fichier
header("Content-disposition: attachment; filename=\"ACH0001".date("YmdHis").".txt\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: application/vnd.ms-excel\n");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
header("Expires: 0");

echo $outputCsv;
exit();
?>

Re: Problème conversion champ en longueur fixe

Posté : 12 mars 2012, 19:15
par sirakawa
Dans mon innocence, je croyais que les fichiers au format C(omma)S(eparated)V(alue) comportaient des lignes dont les diverses données étaient séparées par un symbole, dans la version primitive, la virgule, maintenant virgule, point-virgule, deux points, tabulation, j'en passe et des pires.
Mais peut-être me trompetté-je...