5
$\begingroup$

I am trying to export some floating point numbers into a csv/txt file. I would like to have a efficient way to control the space between numbers as well as the accuracy of the numbers, as we do in C:

 fprintf(
   fname, "%9.5f, %9.5f, %9.5f, %9.5f, %d\n", 
   y[i][1], y[i][2], y[i][3], y[i][4], d[i]
 );

Here "%9.5f" is exactly what I want to implement in Mathematica. I searched for hours and can not get a good solution. NumberForm and PaddedForm only change the printing format, while others like SetAccuracy does not control the spaces. Any ideas? Many thanks.

$\endgroup$
  • $\begingroup$ Did any of the answers satisfied your need? There are things to do after your question is answered. It's a good idea to stay vigilant for some time, better approaches may come later improving over previous replies. Experienced users may point alternatives, caveats or limitations. New users should test answers before voting and wait 24 hours before accepting the best one. One weeks is enough wait. Participation is essential for the site, please do your part. $\endgroup$ – rhermans Jul 9 '18 at 22:34
2
$\begingroup$

The NumberFormoption NumberPadding does exactly what you want:

StringTemplate["``, ``"] @@ (
  NumberForm[#, {9, 5}, NumberPadding -> {" ", "0"}] & /@ {3.1, 5.1}
)

(* "    3.10000,     5.10000" *)
$\endgroup$
0
$\begingroup$

Mathematica has no real sprintf- or fprintf-equivalents. Others have asked about the problem.

  1. Can StringTemplate be extended to offer printf-like formatting capabilities?
  2. sprintf() or close equivalent, or re-implementation?

We can, however, simulate sprintf format with Mathematica functions and a bit of manipulation. Here are some sample values to demonstrate the problems with direct use of NumberForm.

samples = {1.123, 12.12345, -12.12345, 123.12345,
  1234.12345, -123.12345, -123.123455};

This is the expected result for samples using sprintf and %9.5f format.

1.123       "  1.12300"
12.12345    " 12.12345"
-12.12345   "-12.12345"
123.12345   "123.12345"
1234.12345  "1234.12345"
-123.12345  "-123.12345"
-123.123455 "-123.12346"

Let's try to create the same result in Mathematica. Unfortunately, NumberForm does not duplicate sprintf.

numberform = 
  ToString@NumberForm[#, {9, 5}, NumberPadding -> {" ", "0"}] & /@ samples;

The length of the NumberForm strings is 11, but the length of sprintf strings is 9 before overflow. A fix is to trim one or two leading blanks from the NumberForm strings with StringTrim. Here's a comparison of sprintf, using NumberForm alone, and combining StringTrim[#, RegularExpression["^ {1,2}"]] with NumberForm.

sprintf       NumberForm     StringTrim
"  1.12300"   "    1.12300"  "  1.12300"
" 12.12345"   "   12.12345"  " 12.12345"
"-12.12345"   "  -12.12345"  "-12.12345"
"123.12345"   "  123.12345"  "123.12345"
"1234.12345"  " 1234.12345"  "1234.12345"
"-123.12345"  " -123.12345"  "-123.12345"
"-123.12346"  " -123.12346"  "-123.12346"

To simulate how fprintf would work with some sample data, first, convert the floating-point values in y to sprintf format. Convert the value in d to a string with ToString[IntegerPart[d[[i]]]]. Next, separate the sprintf strings with comma and a space: ", ". Here are some sample values for y and d.

SeedRandom[1]
y = RandomReal[{-99, 99}, {1, 4}];
d = RandomInteger[10, 4];
i = 1;

floats = StringTrim[#, RegularExpression["^ {1,2}"]] & /@
 (ToString@NumberForm[#, {9, 5}, NumberPadding -> {" ", "0"}] & /@ 
   y[[i]]);

s = StringJoin[
   Riffle[Flatten@{floats, ToString[IntegerPart[d[[i]]]]}, ", "]
   ];

s // InputForm

The result, s, simulates the output of sprintf("%9.5f, %9.5f, %9.5f, %9.5f, %d", ...).

" 62.84312, -76.93892,  57.32615, -61.81498, 3"

Finally, save the formatted values to a text file.

Export[SystemDialogInput["FileSave", "fname.txt"], s]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.