You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/Format.jl
+186-3Lines changed: 186 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,195 @@
1
-
__precompile__(true)
1
+
"""
2
+
Format.jl
2
3
4
+
This package provides various functions to provide formatted output,
5
+
either in a fashion similar to C printf or Python format strings.
6
+
7
+
## Python-style Types and Functions
8
+
9
+
#### Types to Represent Formats
10
+
11
+
This package has two types ``FormatSpec`` and ``FormatExpr`` to represent a format specification.
12
+
13
+
In particular, ``FormatSpec`` is used to capture the specification of a single entry. One can compile a format specification string into a ``FormatSpec`` instance as
14
+
15
+
```julia
16
+
fspec = FormatSpec("d")
17
+
fspec = FormatSpec("<8.4f")
18
+
```
19
+
Please refer to [Python's format specification language](http://docs.python.org/2/library/string.html#formatspec) for details.
20
+
21
+
22
+
``FormatExpr`` captures a formatting expression that may involve multiple items. One can compile a formatting string into a ``FormatExpr`` instance as
23
+
24
+
```julia
25
+
fe = FormatExpr("{1} + {2}")
26
+
fe = FormatExpr("{1:d} + {2:08.4e} + {3|>abs2}")
27
+
```
28
+
Please refer to [Python's format string syntax](http://docs.python.org/2/library/string.html#format-string-syntax) for details.
29
+
30
+
31
+
**Note:** If the same format is going to be applied for multiple times. It is more efficient to first compile it.
32
+
33
+
34
+
#### Formatted Printing
35
+
36
+
One can use ``printfmt`` and ``printfmtln`` for formatted printing:
37
+
38
+
- **printfmt**(io, fe, args...)
39
+
40
+
- **printfmt**(fe, args...)
41
+
42
+
Print given arguments using given format ``fe``. Here ``fe`` can be a formatting string, an instance of ``FormatSpec`` or ``FormatExpr``.
If the first argument is a string, it will be first compiled into a ``FormatExpr``, which implies that you can not use specification-only string in the first argument.
60
+
61
+
```julia
62
+
printfmt("{1:d}", 10) # OK, "{1:d}" can be compiled into a FormatExpr instance
63
+
printfmt("d", 10) # Error, "d" can not be compiled into a FormatExpr instance
64
+
# such a string to specify a format specification for single argument
65
+
66
+
printfmt(FormatSpec("d"), 10) # OK
67
+
printfmt(FormatExpr("{1:d}", 10)) # OK
68
+
```
69
+
70
+
71
+
- **printfmtln**(io, fe, args...)
72
+
73
+
- **printfmtln**(fe, args...)
74
+
75
+
Similar to ``printfmt`` except that this function print a newline at the end.
76
+
77
+
#### Formatted String
78
+
79
+
One can use ``pyfmt`` to format a single value into a string, or ``format`` to format one to multiple arguments into a string using an format expression.
80
+
81
+
- **pyfmt**(fspec, a)
82
+
83
+
Format a single value using a format specification given by ``fspec``, where ``fspec`` can be either a string or an instance of ``FormatSpec``.
84
+
85
+
- **format**(fe, args...)
86
+
87
+
Format arguments using a format expression given by ``fe``, where ``fe`` can be either a string or an instance of ``FormatSpec``.
88
+
89
+
90
+
#### Difference from Python's Format
91
+
92
+
At this point, this package implements a subset of Python's formatting language (with slight modification). Here is a summary of the differences:
93
+
94
+
- ``g`` and ``G`` for floating point formatting have not been supported yet. Please use ``f``, ``e``, or ``E`` instead.
95
+
96
+
- The package currently provides default alignment, left alignment ``<`` and right alignment ``>``. Other form of alignment such as centered alignment ``^`` has not been supported yet.
97
+
98
+
- In terms of argument specification, it supports natural ordering (e.g. ``{} + {}``), explicit position (e.g. ``{1} + {2}``). It hasn't supported named arguments or fields extraction yet. Note that mixing these two modes is not allowed (e.g. ``{1} + {}``).
99
+
100
+
- The package provides support for filtering (for explicitly positioned arguments), such as ``{1|>lowercase}`` by allowing one to embed the ``|>`` operator, which the Python counter part does not support.
101
+
102
+
## C-style functions
103
+
104
+
The c-style part of this package aims to get around the limitation that
105
+
`@sprintf` has to take a literal string argument.
106
+
The core part is basically a c-style print formatter using the standard
107
+
`@sprintf` macro.
108
+
It also adds functionalities such as commas separator (thousands), parenthesis for negatives,
109
+
stripping trailing zeros, and mixed fractions.
110
+
111
+
### Usage and Implementation
112
+
113
+
The idea here is that the package compiles a function only once for each unique
114
+
format string within the `Format.*` name space, so repeated use is faster.
115
+
Unrelated parts of a session using the same format string would reuse the same
116
+
function, avoiding redundant compilation. To avoid the proliferation of
117
+
functions, we limit the usage to only 1 argument. Practical consideration
118
+
would suggest that only dozens of functions would be created in a session, which
119
+
seems manageable.
120
+
121
+
Usage
122
+
```julia
123
+
using Format
124
+
125
+
fmt = "%10.3f"
126
+
s = cfmt( fmt, 3.14159 ) # usage 1. Quite performant. Easiest to switch to.
127
+
128
+
fmtrfunc = generate_formatter( fmt ) # usage 2. This bypass repeated lookup of cached function. Most performant.
129
+
s = fmtrfunc( 3.14159 )
130
+
131
+
s = format( 3.14159, precision=3 ) # usage 3. Most flexible, with some non-printf options. Least performant.
132
+
```
133
+
### Speed
134
+
135
+
`cfmt`: Speed penalty is about 20% for floating point and 30% for integers.
136
+
137
+
If the formatter is stored and used instead (see the example using `generate_formatter` above),
138
+
the speed penalty reduces to 10% for floating point and 15% for integers.
139
+
140
+
### Commas
141
+
142
+
This package also supplements the lack of thousand separator e.g. `"%'d"`, `"%'f"`, `"%'s"`.
143
+
144
+
Note: `"%'s"` behavior is that for small enough floating point (but not too small),
145
+
thousand separator would be used. If the number needs to be represented by `"%e"`, no
146
+
separator is used.
147
+
148
+
### Flexible `format` function
149
+
150
+
This package contains a run-time number formatter `format` function, which goes beyond
151
+
the standard `sprintf` functionality.
152
+
153
+
An example:
154
+
```julia
155
+
s = format( 1234, commas=true ) # 1,234
156
+
s = format( -1234, commas=true, parens=true ) # (1,234)
157
+
```
158
+
159
+
The keyword arguments are (Bold keywards are not printf standard)
160
+
161
+
* width. Integer. Try to fit the output into this many characters. May not be successful.
162
+
Sacrifice space first, then commas.
163
+
* precision. Integer. How many decimal places.
164
+
* leftjustified. Boolean
165
+
* zeropadding. Boolean
166
+
* commas. Boolean. Thousands-group separator.
167
+
* signed. Boolean. Always show +/- sign?
168
+
* positivespace. Boolean. Prepend an extra space for positive numbers? (so they align nicely with negative numbers)
169
+
* **parens**. Boolean. Use parenthesis instead of "-". e.g. `(1.01)` instead of `-1.01`. Useful in finance. Note that
170
+
you cannot use `signed` and `parens` option at the same time.
171
+
* **stripzeros**. Boolean. Strip trailing '0' to the right of the decimal (and to the left of 'e', if any ).
172
+
* It may strip the decimal point itself if all trailing places are zeros.
173
+
* This is true by default if precision is not given, and vice versa.
174
+
* alternative. Boolean. See `#` alternative form explanation in standard printf documentation
175
+
* conversion. length=1 string. Default is type dependent. It can be one of `aAeEfFoxX`. See standard
176
+
printf documentation.
177
+
* **mixedfraction**. Boolean. If the number is rational, format it in mixed fraction e.g. `1_1/2` instead of `3/2`
178
+
* **mixedfractionsep**. Default `_`
179
+
* **fractionsep**. Default `/`
180
+
* **fractionwidth**. Integer. Try to pad zeros to the numerator until the fractional part has this width
181
+
* **tryden**. Integer. Try to use this denominator instead of a smaller one. No-op if it'd lose precision.
182
+
* **suffix**. String. This strings will be appended to the output. Useful for units/%
183
+
* **autoscale**. Symbol, default `:none`. It could be `:metric`, `:binary`, or `:finance`.
184
+
* `:metric` implements common SI symbols for large and small numbers e.g. `M`, `k`, `μ`, `n`
185
+
* `:binary` implements common ISQ symbols for large numbers e.g. `Ti`, `Gi`, `Mi`, `Ki`
186
+
* `:finance` implements common finance/news symbols for large numbers e.g. `b` (billion), `m` (millions)
0 commit comments