Did you know ... Search Documentation:
SWI-Prolog owl logo Predicate format/2
Availability:built-in
format(+Format, :Arguments)
Format is an atom, list of character codes, or a Prolog string. Arguments is a list of arguments required by the format specification. For backward compatibility, if Format needs exactly one argument and the required argument is not a list, single argument needs not be nested in a list. This feature is deprecated as it easily leads to mistakes and make static analysis by check/0 less accurate.

Special sequences start with the tilde (~), followed by an optional numeric argument, optionally followed by a colon modifier (:), 145The colon modifiers is a SWI-Prolog extension, proposed by Richard O'Keefe. followed by a character describing the action to be undertaken. A numeric argument is either a sequence of digits, representing a positive decimal number, a sequence ‘<character>, representing the character code value of the character (only useful for ~t) or a asterisk (*), in which case the numeric argument is taken from the next argument of the argument list, which should be a positive integer. E.g., the following three examples all pass 46 (.) to ~t:

?- format('~w ~46t ~w~72|~n', ['Title', 'Page']).
?- format('~w ~`.t ~w~72|~n', ['Title', 'Page']).
?- format('~w ~*t ~w~72|~n', ['Title', 46, 'Page']).

Some format expressions may call back Prolog, i.e., ~p, ~W, ~@ and user defined extensions registered with format_predicate/2. Output written to the stream current_output is merged into the format/2 output. If there is no pending rubber (~t) and the the position notation aligns, only the output is switched. Otherwise the output is captured in a temporary memory buffer and emitted after the callback finishes. The system attempts to preserve the position and alignment promises. It sets the tty property of the temporary stream to reflect the main stream and uses the position information of the temporary stream to update its notion of the position. Notable ansi_format/3 cooperates properly in callbacks.146As of version 8.3.30.

Numeric conversion (d, D, e, E, f, g, G, h and H) accept an arithmetic expression as argument. This is introduced to handle rational numbers transparently (see section 4.27.2.2). The floating point conversions allow for unlimited precision for printing rational numbers in decimal form. E.g., the following will write as many 3's as you want by changing the‘50’.

?- format('~50f', [10 rdiv 3]).
3.33333333333333333333333333333333333333333333333333
  • ~
    Output the tilde itself.
  • a
    Output the next argument, which must be an atom. This option is equivalent to w, except that it requires the argument to be an atom.
  • c
    Interpret the next argument as a character code and add it to the output. This argument must be a valid Unicode character code. Note that the actually emitted bytes are defined by the character encoding of the output stream and an exception may be raised if the output stream is not capable of representing the requested Unicode character. See section 2.18.1 for details.
  • d
    Output next argument as a decimal number. It should be an integer. If a numeric argument is specified, a dot is inserted argument positions from the right (useful for doing fixed point arithmetic with integers, such as handling amounts of money).

    The colon modifier (e.g., ~:d) causes the number to be printed according to the locale of the output stream. See section 4.23.

  • D
    Same as d, but makes large values easier to read by inserting a comma every three digits left or right of the dot. This is the same as ~:d, but using the fixed English locale. If D is modified using the colon (~:D), it uses the Prolog grouping character _. See also setup_prolog_integer_grouping/0. Future versions may also support line breaks in big integers.
  • e
    Output next argument as a floating point number in exponential notation. The numeric argument specifies the precision. Default is 6 digits. Exact representation depends on the C library function printf(). This function is invoked with the format %.<precision>e.
  • E
    Equivalent to e, but outputs a capital E to indicate the exponent.
  • f
    Floating point in non-exponential notation. The numeric argument defines the number of digits right of the decimal point. If the numeric argument is zero (0), the value is printed as an integer. If the colon modifier (:) is used, the float is formatted using conventions from the current locale, which may define the decimal point as well as grouping of digits left of the decimal point.
  • g
    Floating point in e or f notation, whichever is shorter.
  • G
    Floating point in E or f notation, whichever is shorter.
  • h
  • H
    Print a floating point number with the minimal number of digits such that read/1 produces exactly (as in ==/2) the same number. The argument specifies whether a number is written using exponential notation (using e (h) or E (H)) or fixed point notation (as ~f). If the argument is -1, the number is always written using exponential notation. Otherwise, number is written using exponential notation if the exponent is less than Arg-1 or greater than Arg+d, where d is the number of digits emitted to establish the required precision. Using an argument larger than the the maximum exponent such as ~999h never uses exponential notation. The default argument is 3. The predicate write/1 and friends act as if using the format ~3h. This option is compatible to SICStus Prolog.
  • i
    Ignore next argument of the argument list. Produces no output.
  • I
    Emit a decimal number using Prolog digit grouping (the underscore, _). The argument describes the size of each digit group. The default is 3. See also section 2.15.1.5. For example:
    ?- A is 1<<100, format('~10I', [A]).
    1_2676506002_2822940149_6703205376
  • k
    Give the next argument to write_canonical/1.
  • n
    Output a newline character.
  • N
    Only output a newline if the last character output on this stream was not a newline. Not properly implemented yet.
  • p
    Give the next argument to print/1.
  • q
    Give the next argument to writeq/1.
  • r
    Print integer in radix numeric argument notation (default 8). Thus ~16r prints its argument hexadecimal. The argument should be in the range [2, ... , 36]. Lowercase letters are used for digits above 9. The colon modifier may be used to form locale-specific digit groups.
  • R
    Same as r, but uses uppercase letters for digits above 9.
  • s
    Output text from a list of character codes, characters, string (see string/1 and section 5.2) or atom from the next argument. If an numeric argument is given the string is truncated to this number of characters.
  • @
    Interpret the next argument as a goal and execute it. Output written to the current_output stream is inserted at this place. Goal is called in the module calling format/3. This option is not present in the original definition by Quintus, but supported by some other Prolog systems. The goal is executed as \+ \+ Goal, i.e., bindings created by the goal are discarded.
  • t
    All remaining space between 2 tab stops is distributed equally over ~t statements between the tab stops. This space is padded with spaces by default. If an argument is supplied, it is taken to be the character code of the character used for padding. This can be used to do left or right alignment, centering, distributing, etc. See also ~| and ~+ to set tab stops. A tab stop is assumed at the start of each line.
  • |
    Set a tab stop on the current position. If an argument is supplied set a tab stop on the position of that argument. This will cause all ~t’s to be distributed between the previous and this tab stop.

    If the current column is at or past the requested tabstop and the modifier (:) is used, a newline is inserted and the padding character of the last ~t is used to pad to the requested position.

  • +
    Set a tab stop (as ~|) relative to the last tab stop or the beginning of the line if no tab stops are set before the ~+. This constructs can be used to fill fields. The partial format sequence below prints an integer right-aligned and padded with zeros in 6 columns. The ... sequences in the example illustrate that the integer is aligned in 6 columns regardless of the remainder of the format specification.
     format('...~|~`0t~d~6+...', [..., Integer, ...])
  • w
    Give the next argument to write/1.
  • W
    Give the next two arguments to write_term/2. For example, format('~W', [Term, [numbervars(true)]]). This option is SWI-Prolog specific.

Example:

simple_statistics :-
 <obtain statistics> % left to the user
 format('~tStatistics~t~72|~n~n'),
 format('Runtime: ~`.t ~2f~34| Inferences: ~`.t ~D~72|~n',
 [RunT, Inf]),
 ....

will output

 Statistics
Runtime: .................. 3.45 Inferences: .......... 60,345
Tags are associated to your profile if you are logged in|Report abuse
Tags:
  • doc-needs-help
  • zero-padding-integers
Jan Wielemaker said (2013年07月10日T15:23:01):2 upvotes 2 0 downvotes
Picture of user Jan Wielemaker.

Use the format string below to realize zero-padded integers. Explanation:

  • ~| sets a tab-stop, so we can use ~5+ to set one 5 positions further.
  • ~`0t pads the space between the two tab-stops that is not occupied by the integer with 0s
    ?- format('Solution ~|~`0t~d~5+', [42]).
    Solution 00042
LogicalCaptain said (2020年01月20日T22:30:13):0 upvotes 0 0 downvotes
Picture of user LogicalCaptain.

Print hex codes

0-padded 4-nibbles:

?- Code=6464, format(atom(T),"0x~|~`0t~16r~4+",[Code]).
Code = 6464,
T = '0x1940'.

Cheatsheet

A cheatsheet for format/2 can be grabbed here:

Maybe missing

An option which takes two elements from the Arguments list, the format string and the value.

Supposing we use &, one could then do:

?- format("This is a float: ~&~n",[f,0.12]).
This is a float: 0.120000
true.
?- format("This is a float: ~&~n",[g,0.12]).
This is a float: 0.12
true.

etc. Seems reasonable for a dynamically typed language.

Note the quoting

String, with or without spaces, formatted using ~q or ~s:

?- format("~s",["a b"]).
a b
true.
?- format("~q",["a b"]).
"a b"
true.
?- format("~s",["ab"]).
ab
true.
?- format("~q",["ab"]).
"ab"
true.

Similar to atom:

?- format("~a",['a b']).
a b
true.
?- format("~q",['a b']).
'a b'
true.
?- format("~a",[ab]).
ab
true.
?- format("~q",[ab]).
ab
true.

Where exactly does the output go?

I guess it goes to whatever is "currently" denoted by current_ouput. That would generally be the same as user_output, i.e. stdout.

See Predefined stream aliases

To direct the output elsewhere, you will have to change the current_output with with_output_to/2 or use format/3. The latter is more practical.

More on various printing predicates

For those looking for the correct predicate to use:

Check the format string

This pack provides (I haven't tested it yet):

https://www.swi-prolog.org/pack/list?p=format_spec

From the toolbox: Defensive programming around format calls

format/2 is precise in the arguments it expects and will throw if there are too many or too few arguments.

If you want to make sure a call to format/2 won't generate further exceptions in situations where you are already handling an exception for example here:

safe_format.pl

?- safe_format("Hello ~d",[7889],Result).
Result = "Hello 7889".
?- safe_format("Hello ~d",[hello],Result).
Result = "Exception in format/3 with format string <Hello ~d> and args <hello>".
?- safe_format("Open the ~s.",["pod bay doors","HAL"],Result).
Result = "Exception in format/3 with format string <Open the ~s.> and args <\"pod bay doors\">,<\"HAL\">".

Actually, there is a non-exported '$messages':safe_format/3 in file messages.pl already. Good stuff:

safe_format(S, Fmt, Args) :-
 E = error(_,_), % avoid repeating error(X,Y)
 catch(format(S,Fmt,Args), E,
 format_failed(S,Fmt,Args,E)).
format_failed(S, _Fmt, _Args, E) :-
 E = error(io_error(_,S),_), % if it's I/O error, rethrow!
 !,
 throw(E).
format_failed(S, Fmt, Args, error(E,_)) :-
 format(S, '~N [[ EXCEPTION while printing message ~q~n\c
 ~7|with arguments ~W:~n\c
 ~7|raised: ~W~n~4|]]~n',
 [ Fmt,
 Args, [quoted(true), max_depth(10)], % emitted with write_term/2
 E, [quoted(true), max_depth(10)] % emitted with write_term/2
 ]).

Justify text left, right or centered

You can use the format/2 tabstop markers directly and flexibly.

For example, a program that builds a format string to set tabstops and print "Hello" into that space, center-justified (with + used as whitespace on the left, * used as whitespace on the right):

several_strings :-
 Ch1=0'+, % a codepoint
 Ch2=0'*, % a codepoint
 bagof(X,between(0,20,X),Positions), % a list 0..20
 maplist(
 {Ch1,Ch2}/[P,F]>>
 atomics_to_string(["~|","~",Ch1,"t","~s","~",Ch2,"t","~",P,"+"],F),
 Positions,
 FormatStrings),
 maplist(
 [F]>>
 (format("The format string is ~q, The formatted string is ",[F]),
 format(F,["Hello"]),
 format("~n")),
 FormatStrings).

Sample output:

The format string is "~|~43t~s~42t~5+", The formatted string is Hello
The format string is "~|~43t~s~42t~6+", The formatted string is Hello*
The format string is "~|~43t~s~42t~7+", The formatted string is +Hello*
The format string is "~|~43t~s~42t~8+", The formatted string is +Hello**
The format string is "~|~43t~s~42t~9+", The formatted string is ++Hello**
The format string is "~|~43t~s~42t~10+", The formatted string is ++Hello***

Note that the tabstop position markers are all relative instead of absolute. This is needed because the absolute tabpositions are positions in the output line, not the string generated by "format" (so format seems to consult the status of the current line in current_output). As the intro "The format string ..." is of variable length, absolute positions relative to the line would not work and absolute positions relative to the string would be a swamped by a sufficently long intro.

Note that tabstop position 0 is after character 0, counted from 0 (as expected):

?- format("~42t~0|<\n"). % tabstop at 0, there are no characters to fill in with ~t
<
?- format("~42t~1|<\n"). % tabstop at 1, there is 1 characters to fill in with ~t
*<
?- format("~42t~2|<\n"). % tabstop at 2, there are 2 characters to fill in with ~t
**<

From the toolbox: Justify text left, right or centered

I did my own code for "string justification" as programming exercise, this becomes complex quickly:

README_stringy_justify.md

?- justify_how(left,10,"hello",Result,string).
Result = "hello ".

etc.

Playing with floats

This little example prints a float, reads it back and compares:

Note that float are IEEE 754 64-bit floats, which have 53 binary digits, thus 15.95 decimal digits of precision between 1.0 and 2.0.

At a precision of 16 decimal digits, the difference to what is read back in is 0 (or rather, it underflows to 0?).

Adding more precision makes the printer hallucinate meaningless additional digits of precision. Fun!

several_floats :-
 V is sqrt(2),
 assertion(float(V)),
 bagof(X,between(0,20,X),Positions), % a list 0..20
 maplist({V}/[P,F]>>atomics_to_string(["~",P,"e"],F),Positions,FormatStrings),
 maplist(
 {V}/[F]>>(
 format("The format string is ~q",[F]),
 format(string(FormyV),F,[V]),
 format(", The formatted string is ~s",[FormyV]),
 string_codes(FormyV,Cs),
 phrase(float(ReadV),Cs),
 assertion(float(ReadV)),
 Delta is V-ReadV,
 format(", The difference to the read-back value is ~e",[Delta]),
 format("~n")),
 FormatStrings).
The format string is "~13e", The formatted string is 1.4142135623731e+00, The difference to the read-back value is -4.884981e-15
The format string is "~14e", The formatted string is 1.41421356237310e+00, The difference to the read-back value is -4.884981e-15
The format string is "~15e", The formatted string is 1.414213562373095e+00, The difference to the read-back value is 2.220446e-16
The format string is "~16e", The formatted string is 1.4142135623730951e+00, The difference to the read-back value is 0.000000e+00
The format string is "~17e", The formatted string is 1.41421356237309515e+00, The difference to the read-back value is 0.000000e+00
The format string is "~18e", The formatted string is 1.414213562373095145e+00, The difference to the read-back value is 0.000000e+00

Inline function call

SWI-Prolog has dicts. Predicates can be associated to those, and they behave like function calls. This gives us function calls beyond the arithmetic evaluation of is/2. In particular, for strings you can do things like this:

Define a module called string to associate functions to dicts with tag string (there is a problem in that modules are not hierarchical so you may end up with a name clash in the unique global module space, but, let's disregard this for now):

:- module(string,[]).
% This is a predicate format/3 written as a function format/2 (maybe there
% needs to be a new descriptor syntax: format///2 ?) taking a dict tagged as
% "string" and two arguments which evaluates to the value of variable Text.
S.format(Msg,Args) := Text :- with_output_to(string(Text),format(Msg,Args)).

Once the above module has been loaded, you can do things like these, which behave like a Java "static" method call (you can move args into the dict too of course):

?- X=string{}.format("Hello, ~q\n",["World"]).
X = "Hello, \"World\"\n".
?- debug(foo),debug(foo,string{}.format("Hello, ~q\n",["World"]),[]).
% Hello, "World"

More tricks

Generates a string of 2 spaces in Spaces:

format(string(Spaces), '~t~*|', [2]).
  • because ~t soaks up positions between the 0th and the 1st tab stop and generates space characters
  • `~*|` sets the next tab stop at the position given by the value in the arglist, i.e. at position 2.

Related: Tabular data

I always wanted to print tabular data in Prolog. Here is a dirt simple way of doing it (still has rough edges, prerelesase):

Prints things like these based on a table description made with a dict:

?- test_tablify(X).
+------+--------+------------+--------------+------------+------+
| Name | Prior | Local cost | Overall cost | State | Hops |
+------+--------+------------+--------------+------------+------+
| a | | 100 | 1000000 | visit_next | 100 |
| b | calpha | 10 | 100 | probed | 100 |
+------+--------+------------+--------------+------------+------+

There are packs offering this functionality:

How to prettyprint a dict

For example:

?- dict_pp(various{w: 0.25984759, ww: 1.4587598, www: 643764856, wwww: 400},
 _{pad_left:5,pad_right:4,pad:true}).
 various
 w : 0.259848
 ww : 1.458760
 www : 643764856
 wwww : 400
true.
?- dict_pp(various{w: 0.25984759, ww: 1.4587598, www: 643764856, wwww: 400},
 _{pad:true,pad_left:2,pad_top:1,pad_bottom:1,pad_right:2,
 border:true,justify_tag:left,justify_tag_full:false}).
+--------------------+
| various |
+--------------------+
| |
| w : 0.259848 |
| ww : 1.458760 |
| www : 643764856 |
| wwww : 400 |
| |
+--------------------+
true.
?- dict_pp(alpha{w1: 10, w2: 200, w3: 3000,
 w4: bravo{w1: 10, w2: 20,
 w3: charlie{ a: 12, b: 13}}},
 _{border:true,tag:false}).
+--------------------+
|w1 : 10 |
|w2 : 200 |
|w3 : 3000 |
|w4 : +-------------+|
| |w1 : 10 ||
| |w2 : 20 ||
| |w3 : +------+||
| | |a : 12|||
| | |b : 13|||
| | +------+||
| +-------------+|
+--------------------+
true.
Paul Singleton said (2017年05月16日T17:21:55):0 upvotes 0 0 downvotes
Picture of user Paul Singleton.
The second arg :Arguments isn't really a meta-argument, just because a "~@" sequence can cause a member of Arguments to be interpreted as a goal and executed (yuk!). How can I stop any predicate of mine which passes one of its args to format/2 being flagged as an "Undeclared Meta Predicate" in PDT?
Simon Clematide said (2015年09月17日T16:59:44):0 upvotes 0 0 downvotes
Picture of user Simon Clematide.

I noted that Swi prolog 7 now quotes atoms formatted by ~p. Yap and earlier versions of swi prolog did not do that. Using ~w seems to be the solution for unquoted output.

SWI7

?- format('#~p#\n',['']).
#''#
true.

YAP

?- format('#~p#\n',['']).
##
yes
login to add a new annotation post.

AltStyle によって変換されたページ (->オリジナル) /