Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run-time string formatting #5866

Closed
lindahua opened this issue Feb 20, 2014 · 13 comments
Closed

Run-time string formatting #5866

lindahua opened this issue Feb 20, 2014 · 13 comments

Comments

@lindahua
Copy link
Contributor

I several applications that I recently worked on, I find the need to do runtime string formatting -- something like:

function foo(...; fmt::String="{1:%.4f} - {2:%.4f}")
    ....
    printf(fmt, x, y)
    ....
end

The @printf macro obviously does not do the trick, as it requires the formatting string to be fixed before compile-time. I ended up writing several overly-simplified & not-so-general version of such a printf & sprintf functions.

I know that Musache.jl provides run-time string templates. But it seems to be too heavy-weight for simple string formatting needs and does not support C-style convenient format specification, e.g. %f, %d etc.

I would be great to provide such machinery in the base. Here is a tentative outline of the API design:

fmt = Formatter( spec )   # e.g. fmt = Formatter( "%d" )

printfmt(io, fmt, args ...)  # print formatted text to IO
printfmt(fmt, args ...) = printfmt(STDOUT, fmt, args ...)   # print formatted text to standard IO

function format(fmt, args ... ) # produce a string
    buf = IOBuffer()
    printfmt(buf, fmt, args ...)
    bytestring(buf)
end

printfmt(io, spec, args ...) = printfmt(Formatter(spec), args ...)
printfmt(spec, args ...) = printfmt(Formatter(spec), args ...)
format(spec, args ...) = format(Formatter(spec), args ...)
@JeffBezanson
Copy link
Member

I'd like to have a function call interface to the machinery inside printf; e.g. a function that accepts the number of digits to print as an argument. Having all such things go through format strings seems silly.

Just curious --- in your use case, what aspect of the formatting changes at run time?

@lindahua
Copy link
Contributor Author

The use case is that the user will use a config file to specify how they format each row of a report, as

rowfmt = "%10d, %10d, %10.5f ---- %10.5f %-10s"

A report generation function will load the config, and apply it write the experimental results to a text file.

I think something like the python format (http://docs.python.org/2/library/string.html#formatspec) is ideal.

@JeffBezanson
Copy link
Member

In that case, there is only one format string determined at startup, so you could use

formatter = @eval (io,args...)->@printf(io, $fmt, args...)

@lindahua
Copy link
Contributor Author

In many cases, formatting is not as simple as just to format a single number.

@lindahua
Copy link
Contributor Author

The problem is that fmt is read from a user-provided config file and can not be hard coded in the source file. I don't know how such an fmt can be fit in that macro.

@StefanKarpinski
Copy link
Member

You can read the config file and define a global formatter function which you then call later.

@JeffBezanson
Copy link
Member

That works fine in my example:

fmt = readline(file)
formatter = @eval (io,args...)->@printf(io, $fmt, args...)

It's obvious that formatting deals with more than single numbers. That is just an example of one primitive you'd need to have all the features of printf be run-time values.

@lindahua
Copy link
Contributor Author

This works. I am not going to continue to pursue this feature.

However, exposing some of the machinates underlying @printf would be useful.

@IainNZ
Copy link
Member

IainNZ commented Sep 30, 2014

Is there a follow up issue to this? I need this and its kind of awkward we don't have a good answer for it.

@JeffBezanson
Copy link
Member

Could you describe your use case? Does my formatter hack above work for you?

@IainNZ
Copy link
Member

IainNZ commented Sep 30, 2014

It does work, yes. Use-case is basically building functionality on top of @sprintf, e.g. this:
https://github.com/jmoiron/humanize/blob/master/humanize/filesize.py
I've translated it to https://github.com/IainNZ/Humanize.jl/blob/master/src/filesize.jl, but it feels like a bit of a hack (@eval code smell)

@tonyhffong
Copy link

Would this be helpful? https://github.com/tonyhffong/NumFormat.jl

I wouldn't say the underlying code doesn't have smell. But at the surface it works nicely and the speed is the closest to native macro among many alternatives I have tried.

@lindahua
Copy link
Contributor Author

Already have this: https://github.com/lindahua/Formatting.jl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants