Due to @printf being a macro, it does not accept a format string that has been passed as a variable.
myvec = randn(4)
n = length(myvec)
outstring = "Beginning of string with some numbers: "
for i = 1:n
outstring = outstring*"%-12.3g"
end
outstring = outstring*"\n"
@printf(outstring, myvec...)
Is there currently a way to print using format strings without using a macro, or maybe a much smarter way I have failed to understand? The solution provided in
Changes the output for all Float64 which is undesirable in my case.
Itâs been a long-standing issue and I hope it is resolved one day. Iâve been calling libcâs printf directly sometimes. In other situations, the definition
Thanks, in my intended application I will happily pay the performance penalty as long as itâs less than about 0.1s. Your solution seems to solve the problem just fine without the need for an additional package, thanks!
I am personally not very fond of Formatting.jl - not enough lean
A short (and clean i hope) solution can be to gen closure with a macro according to the classical show signature
import Printf
macro gprintf(fmt::String)
:((io::IO, arg) -> Printf.@printf(io, $fmt, arg))
end
# can be used like this
const fi = @gprintf "%d"
const f3p = @gprintf "%.3f"
const f6p = @gprintf "%.6f"
jit_printf(fmt) = @eval @gprintf($fmt)
using Test
@testset "printf_functionalization" begin
@test sprint(f3p, 3.14) == "3.140"
@test sprint(f6p, 3.14) == "3.140000"
@testset for i in 3:8
fmt = string("%.", i, "f")
fjp = @eval @gprintf($fmt) # <=> fjp = jit_printf(fmt)
@test sprint(fjp, 3.14) == "3.14" * repeat('0', i-2)
end
end
PS: BTW @RaulDurand that fix your point, no external package, no eval
still canât use variable format strings with @printf in julia 1.9
julia> using Printf
julia> fmt = "%d"
"%d"
julia> @printf fmt 16
ERROR: LoadError: ArgumentError: First argument to `@printf` after `io` must be a format string
Stacktrace:
[1] var"@printf"(__source__::LineNumberNode, __module__::Module, io_or_fmt::Any, args::Vararg{Any})
@ Printf ~/.julia/juliaup/julia-1.9.0+0.aarch64.apple.darwin14/share/julia/stdlib/v1.9/Printf/src/Printf.jl:943
in expression starting at REPL[3]:1
julia> using Printf
help?> Printf.Format
Printf.Format(format_str)
Create a C printf-compatible format object that can be used
for formatting values.
The input format_str can include any valid format specifier
character and modifiers.
A Format object can be passed to Printf.format(f::Format,
args...) to produce a formatted string, or
Printf.format(io::IO, f::Format, args...) to print the
formatted string directly to io.
For convenience, the Printf.format"..." string macro form
can be used for building a Printf.Format object at
macro-expansion-time.
â Julia 1.6
â
â Printf.Format requires Julia 1.6 or later.
Edit: Sorry, I didnât initially see that this response is identical to that of @fatteneder.
there is a docstring, yes, but what i was pointing out is that neither Printf.format nor Printf.Format are mentioned in the user manual. just trying to make it easier for folks until they are.
Imho, printf should not be a macro in the first place. In the end, its just a small performance optimization precompiling the format string, i.e., it doesnât buy much as compared to its underlying functions:
julia> @macroexpand @printf "%d" 123
:((Printf).format(stdout, Printf.Format{Base.CodeUnits{UInt8, String}, Tuple{Printf.Spec{Val{'d'}}}}(UInt8[0x25, 0x64], UnitRange{Int64}[1:0, 3:2], (%.0d,)), 123))
# So basically the same as
julia> Printf.format(stdout, Printf.format"%d", 123)
123
# i.e. with the format_str macro precompiling the Format
# Why not just define ...
julia> printf(fmt::Printf.Format, args...) = Printf.format(stdout, fmt, args...)
julia> printf(io::IO, fmt::Printf.Format, args...) = Printf.format(io, fmt, args...)
julia> macro fmt_str(s) Printf.Format(s) end
# and be happy
julia> printf(fmt"%d", 123)
123
Am I missing something here, i.e., also Rust decided on format being a macro?