Sprintf équivalent en Mathematica?

Je ne sais pas pourquoi Wikipediarépertorie Mathematica comme un langage de programmation avec printf . Je ne pouvais pas trouver L'équivalent dans Mathematica.

Ma tâche spécifique est de traiter une liste de fichiers de données avec des nombres rembourrés, ce que j'avais l'habitude de faire en bash avec

fn=$(printf "filename_%05d" $n)

La fonction la plus proche que J'ai trouvée dans Mathematica est PaddedForm. Et après quelques essais et erreurs, je l'ai eu avec

"filename_" <> PaddedForm[ Round@#, 4, NumberPadding -> {"0", ""} ]&

Il est très étrange que je doive utiliser le nombre 4 pour obtenir le résultat similaire à ce que j'obtiens à partir de "%05d". Je ne comprends pas ce comportement à tous. Quelqu'un peut-il m'expliquer?

Et est-ce la meilleure façon de réaliser ce que j'ai utilisé dans bash?

25
demandé sur jxy 2009-10-06 20:18:22

5 réponses

Je n'utiliserais pas PaddedForm pour cela. En fait, je ne suis pas sûr que PaddedForm soit bon pour beaucoup de n'importe quoi. Au lieu de cela, j'utiliserais bon vieux ToString, Characters et PadLeft, comme ceci:

toFixedWidth[n_Integer, width_Integer] := 
  StringJoin[PadLeft[Characters[ToString[n]], width, "0"]]

Ensuite, vous pouvez utiliser StringForm et ToString pour créer votre nom de fichier:

toNumberedFileName[n_Integer] :=
  ToString@StringForm["filename_``", toFixedWidth[n, 5]]

Mathematica n'est pas bien adapté à ce genre de grignotage de cordes.

Modifier pour ajouter: Mathematica proprement dit n'a pas les fonctionnalités requises, mais la classe java.lang.String a la méthode statique format() qui prend printf-style argument. Vous pouvez appeler à l'aide de la fonctionnalité JLINK de Mathematica assez facilement. La performance ne sera pas très bonne, mais pour de nombreux cas d'utilisation, vous ne vous en soucierez pas tant que ça:

Needs["JLink`"];
LoadJavaClass["java.lang.String"];
LoadJavaClass["java.util.Locale"];
sprintf[fmt_, args___] :=
 String`format[Locale`ENGLISH,fmt,
  MakeJavaObject /@
   Replace[{args},
    {x_?NumericQ :> N@x,
     x : (_Real | _Integer | True | 
         False | _String | _?JavaObjectQ) :> x,
     x_ :> MakeJavaExpr[x]},
    {1}]]

Vous devez faire un peu plus de travail, car JLink est un peu stupide sur les fonctions Java avec un nombre variable d'arguments. La méthode format() prend une chaîne de format et un tableau de Java Object s, et Mathematica ne fera pas la conversion automatiquement, ce qui est à quoi sert le MakeJavaObject.

9
répondu Pillsy 2015-03-25 15:52:01

J'ai rencontré un peu le même problème et j'ai décidé de coder ma propre fonction. Je ne l'ai pas fait en Java mais j'ai juste utilisé des opérations de chaîne dans Mathematica. Cela s'est avéré assez long, car j'avais aussi besoin de la fonctionnalité %f, mais cela fonctionne, et maintenant je l'ai comme un paquet que je peux utiliser à tout moment. Voici un lien vers le projet GitHub:

Https://github.com/vlsd/MathPrintF

Il est livré avec des instructions d'installation (vraiment juste copier le répertoire quelque part dans le $Path).

J'espère que cela sera utile à au moins certains.

8
répondu vlsd 2011-10-26 15:16:06

Vous pouvez également définir une fonction qui transmet tous les arguments à StringForm [] et utiliser IntegerString ou les fonctions de remplissage comme mentionné précédemment:

Sprintf[args__] := StringForm[args__] // ToString;
file = Sprintf["filename_``", IntegerString[n, 10, 5]];
5
répondu eacousineau 2011-06-13 17:44:23

IntegerString fait exactement ce dont vous avez besoin. Dans ce cas, ce serait

IntegerString[x,10,5]
2
répondu yohai 2014-10-21 20:53:42

Je suis d'accord avec Pillsy. Voici comment je ferais. Notez la fonction cat pratique, que je pense comme un peu comme sprintf (moins les espaces réservés comme stringform fournit) en ce qu'elle fonctionne comme Print (vous pouvez imprimer n'importe quelle concaténation d'expressions sans convertir en String) mais génère une chaîne au lieu d'Envoyer à stdout.

cat = StringJoin@@(ToString/@{##})&;

pad[x_, n_] := If[StringLength@cat[x]>=n, cat[x], 
                                          cat@@PadLeft[Characters@cat[x],n,"0"]]

cat["filename_", pad[#, 5]]&

Cela ressemble beaucoup à la réponse de Pillsy mais je pense que cat le rend un peu plus propre. Aussi, je pense qu'il est plus sûr d'avoir ce conditionnel dans le pad fonction-mieux d'avoir le remplissage mal que le nombre mal.

1
répondu dreeves 2010-04-18 14:28:38