Is there a sprintf()
command (some command that takes a printf
-style format string and a list of values to insert into the string) or something very much like it (preferably with a similar style of format specifiers)? Or, alternately, how would I implement sprintf()
in Mathematica?
6 Answers
I've had a need for such a function several times, and I found this implementation of C-style *printf
functions, by Vlad Seghete. To use it, all you need to do is extract the files to $UserBaseDirectory/MathPrintF/
and you're all set.
Here's an example once you've installed it:
<<MathPrintF`
sprintf["%d %s %d %s, %s %s %s %s",
Sequence @@ Riffle[{1, 2, "red", "blue"}, {"fish"}, {2, -1, 2}]]
Out[1]= 1 fish 2 fish, red fish blue fish
Also note the following caveat in the README
Limited Functionality
While we tried to mimic the C-standard as much as possible, only certain features are implemented. These are mainly dictated by what we needed at the time. In particular %d, %f, %e, %E and %s with most of their options are implemented.
-
$\begingroup$ MathPrintF ist great, but I tested it with 20 "%" commands per line (of different types) and about 20000 lines - MathPrintF is on my computer about 30 to 40 times slower than e.g.
ToString[PaddedForm[..]]
$\endgroup$– lioCommented Jul 14, 2017 at 16:23
Not as such. The closest equivalent is StringForm
, but it doesn't provide the formatting options that the printf
family does. StringForm
gets a lot of use in the creation of messages.
Example:
StringForm["The value of Pi is ``", NumberForm[N[Pi], 3]]
(* ==> "The value of Pi is 3.14" *)
Note that StringForm
does not create a string, it merely displays with a special formatting. It can easily be converted to the equivalent string using ToString@StringForm[...]
though.
-
$\begingroup$ Yes, the formatting has to be done on the control string and parameter strings themselves. E.g.,
StringForm["`1` is in InputForm, while `2` is in TraditionalForm, you see!", InputForm[Exp[x]], TraditionalForm[Exp[x]]]
. $\endgroup$ Commented Jan 30, 2012 at 1:50 -
$\begingroup$ @J.M. exactly. (You need a longer name to allow all of us to enter very short responses to your nuggets of wisdom. And, why yes, I'm intentionally leaving an extra long comment just because.) $\endgroup$– rcollyerCommented Jan 30, 2012 at 2:19
-
$\begingroup$ I thought an example would be in order, please review my edit. $\endgroup$– SzabolcsCommented Jan 30, 2012 at 9:46
-
Mathematica does not have a built-in equivalent to sprintf
. The closest thing is StringForm
which allows placeholders within a string to be replaced, but does not perform any formatting of the replacement values:
sprintf[control_, args___] := StringForm[control, args] // ToString
sprintf["hello, ``", "Joe"]
(* "hello, Joe" *)
Hack #1 - JLink
It is not pretty, but we could use JLink to access Java's printf-like formatting syntax:
Needs["JLink`"]
LoadJavaClass["java.lang.String"];
LoadJavaClass["java.lang.reflect.Array"];
jsprintf[control_, args___] :=
JavaBlock @ Module[{jArgs, array}
, jArgs = MakeJavaObject @ N @ # & /@ {args}
; array = JavaNew["[Ljava.lang.Object;", Length@jArgs]
; MapIndexed[java`lang`reflect`Array`set[array, #2[[1]]-1, #1]&, jArgs]
; java`lang`String`format[control, array]
]
jsprintf["Hello, %s: Pi is %16.14f", "Joe", Pi]
(* "Hello, Joe: Pi is 3.14159265358979" *)
Hack #2 - SQLite
Another way would be to exploit SQLite's built-in printf function. Again it is not pretty but it offers a more faithful replication of C's printf syntax than the JLink solution:
Needs["DatabaseLink`"]
$db = OpenSQLConnection[JDBC["SQLite(Memory)", ""]];
SQLExecute[$db
, "SELECT printf('%10s %3i %10.6f', ?, ?, ?)", {"result", 12, 345.678}
][[1, 1]]
(* " result: 12 345.678000" *)
Hack #3 - NETLink
We could also use NETLink to access C's printf function family directly. This would seem to be the most direct approach but 1) the code varies between platforms and 2) the NETLink C bridge does not handle variable argument lists well. Nevertheless, we could follow the sprintf example from the NETLink documentation about Calling .NET from the Wolfram Language:
nsprintf = DefineDLLFunction[
"sprintf", "msvcrt.dll", "int",
{"System.Text.StringBuilder", "const char*", "const char*", "int", "double"}
];
NETBlock@Module[{sb = NETNew["System.Text.StringBuilder", 1024]}
, nsprintf[sb, "%10s %3i %10.6f", "result", 20, 345.678]
; sb@ToString[]
]
(* " result: 12 345.678000" *)
-
$\begingroup$ python formated print template is little bit different but just for post comprehensiveness,
p1 = ExternalFunction["Python", "def printf(s,*v):\n\treturn s.format(*v)"]
andp2[s_, v__] := RunProcess[{"python", "-c", "print('" <> s <> "'.format(" <> StringJoin@StringRiffle[List@v, ","] <> "),end='')"}, "StandardOutput"]
. example:p1["{} {:.3f}", 2, 45] // AbsoluteTiming
->{0.69001, "2 45.000"}
andp2["{} {:.3f}", 2, 45] // AbsoluteTiming
->{0.0836045, "2 45.000"}
$\endgroup$– Ben IzdCommented Feb 28, 2021 at 22:14 -
$\begingroup$ I should also mention
p2
is not compatible with strings but for numbers is much faster thanp1
. $\endgroup$– Ben IzdCommented Mar 1, 2021 at 8:15
The simple (e.g. non-tabular, no-formatting) case would look something like this.
mmaSprintf[s : {__String}, d_?VectorQ] /; Length[d] == Length[s] :=
StringJoin[Riffle[Riffle[s, ToString /@ d], " "]]
Message has a syntax similar to sprintf()
but not the formatting capabilities. From the documentation:
rsqrt::nnarg = "The argument `1` is not greater than or equal to zero.";
Message[rsqrt::nnarg, x]
As already mentioned before StringForm together with ToString can give functionality that is provided by sprintf in other languages.
Here are some examples that might be useful and avoid any funny mathematica escape sequences in the strings:
myStrings = {
ToString[StringForm["This is a floating point: `1`\n" ,
ToString[NumberForm[5.6 10^9, NumberFormat -> (SequenceForm[#1, "e", #3] &)]]
]],
ToString[StringForm["This is a integer in blocks : `1`\n" ,
ToString[NumberForm[10^9, DigitBlock -> 3]]
]],
ToString[StringForm["This is a number with funny padding : `1` " ,
ToString[NumberForm[6.888, {7, 3}, NumberPadding -> {"_", "0"}]]
]],
ToString[StringForm["This is just a string : `1` " , "FOO"]]
};
myCompleteString = StringJoin[myStrings]
FullForm[myCompleteString]
Export["text.txt", myCompleteString, "Text"]
this will give you:
This is a floating point: 5.6e9
This is a integer in blocks : 1,000,000,000
This is a number with funny padding : ____6.888 This isjust a string : FOO
"This is a floating point: 5.6e9\nThis is a integer in blocks : 1,000,000,000\nThis is a number with funny padding : ____6.888 This is just a string : FOO "
and a file text.txt with the expected output.
See also these discussions:
*) How does string interpolation work in Mathematica
*) Converting a large floating-point number to a single-line string
-
2$\begingroup$ I believe
SequenceForm
has been superseded byRow
. $\endgroup$ Commented Sep 27, 2013 at 10:54
I desperately needed this capability and found Mathematica's string formatting incredibly obtuse and hard to remember.
Therefore, I reimplemented, as well as I could, sprintf
in https://github.com/evanberkowitz/mma-sprintf
The implementation is too long to present here; instead I present the help
?sprintf
gives
%[flags][width][.precision][length]type
flags: [+0-]*
- left align
+ print a plus sign for positive numbers
0 prepend zeros for numeric types, rather than spaces.
width: either * or an unsigned integer. Sets the minimum number of characters to output.
* Consume a parameter, which should be an unsigned integer, and use that as the minimum width.
integer Use the integer directly.
precision: either * or an integer.
* Consume a parameter, which should be an unsigned integer, and use that as the precision.
integer Use the integer directly to set how many digits after the decimal point.
length: hh|ll|[hlLzjt]
Currently does not do any thing at all.
type: [%sScCyYdiuoxXfFeEgGaArR] The convention is that capital letters result in capitalized results.
% Print a literal %
STRINGS
s A literal string
S A literal string, capitalized. EXTENSION!
c A single character.
C A single character, capitalized. EXTENSION!
y Convert unevaluated symbols to strings. EXTENSION!
INTEGERS
d signed int
i signed int
u unsigned int
o unsigned int in octal
x unsigned int in hexadecimal 0x0123456789abcdef
X unsigned int in hexadecimal 0X0123456789ABCDEF
FLOATS
f fixed point, inf, nan
F fixed point, INF, NAN
e scientific notation with an e separator, int.0123456789e\[PlusMinus]power
E scientific notation with an E separator, int.0123456789E\[PlusMinus]power
g
G
a Hexadecimal float 0x[89abcdef].[0123456789abcdef]p\[PlusMinus](power of two)
A Hexadecimal float 0X[89ABCDEF].[0123456789ABCDEF]P\[PlusMinus](power of two)
r TWO fields, a central value and an error. central(error)e\[PlusMinus]power EXTENSION!
R TWO fields, a central value and an error. central(error)E\[PlusMinus]power EXTENSION!
This matches, to the best of my ability, bash's printf, plus useful-to-me extensions.
If you install via make install
(or in whatever your preferred method is) and then run ./example.wls
you will see example output,
>> After installing mathematica/sprintf.wl somewhere Mathematica looks, you can
>> 1234567890123456789012345678901234567890123456789
print strings with %s AND CAPITALIZE THEM WITH %S
strings can be aligned and truncated.
You can get a literal % by using %%.
>> You can also get single characters!
As a Mathematica-specific extension you can stringify SYMBOLs
>> You can format integers with %d or %i.
123456789012345678901234567890
1234 -567890 0 You can omit the + flag and get only minus signs
+1234 -567890 +0 You can use the + flag to demand signs.
>> You can format unsigned integers using %u for decimal, %o for octal, %x for hex, %X for HEX.
%u 1234
%o 2322
%x 4d2
%X 4D2
>> You can left align with a - flag, pad with 0s, and demand signs
12345678901234567890
%+8i +1234
%+-8i +1234
%+08i +000001234
%08i 0000001234
>> You can print things with default or .specified fixed precision
1234567890123456789012345678901234567890
%f %.3f
-π= -3.141593 -3.142
10π= 31.415927 31.416
>> You can print things with default or .specified precision in scientific notation using %e and %E
1234567890123456789012345678901234567890
% %.3
-.1π=-3.141590e-1 -3.141e-1 e
10π= 3.141590E+1 3.140E+1 E
>> You can print floats in hexadecimal using %a or %A.
1234567890123456789012345678901234567890
%a %A
π= 0xc.90fdaap-2 0XC.90FDAA22P-2
>> As a Mathematica extension, here's an uncertainty format %r that consumes two numbers, also understands .precision.
%r %.[varying precisions]r
gA= 1.271(13)e+0 1.27100(1300)e+0 If you request more digits than known, you get zeros.
proton mass/MeV= 9.382720882(3)e+2 9.38272(0)e+2 If the uncertainty smaller than the requested precision, the result may look exact.
proton mass/ kg= 1.6726219237(5)e-27 1.67262192369(51)e-27 If more digits of uncertainty are available, you can force them to appear.
proton charge/ C= 1.602176621(98)e-19 1.60217662(10)e-19 If the uncertainty starts with a 9 an extra digit is printed.
charge radius/fm= 8.414(19)e-1 8.41(2)e-1 If the uncertainty starts with a 1 an extra digit is printed.
Finally, I also include a fprintf[fileStream, formatString, fieldsToPrint]
which sprintf
s the formatted string to the fileStream
and printf
which calls fprintf[$Output,...]
(behaves like Print
unless you've manipulated $Output
).