diff options
author | Araq <rumpf_a@web.de> | 2017-12-17 17:58:04 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2017-12-17 17:58:04 +0100 |
commit | 2e61e6edf99fef44dcfaf23177714a064dbc05fd (patch) | |
tree | a5e73f23a97ec70b9ea336ad70dc82f1fe1fd419 /lib/pure/strformat.nim | |
parent | 5c7493f833443f34f2fa3df36aa4648bc818678d (diff) | |
download | Nim-2e61e6edf99fef44dcfaf23177714a064dbc05fd.tar.gz |
strformat: support 'sign' as Python does
Diffstat (limited to 'lib/pure/strformat.nim')
-rw-r--r-- | lib/pure/strformat.nim | 61 |
1 files changed, 36 insertions, 25 deletions
diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 97dff630e..3feb046b7 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -92,7 +92,7 @@ Standard format specifier The general form of a standard format specifier is:: - [[fill]align][#][0][minimumwidth][.precision][type] + [[fill]align][sign][#][0][minimumwidth][.precision][type] The brackets ([]) indicate an optional element. @@ -116,6 +116,18 @@ The optional 'fill' character defines the character to be used to pad the field to the minimum width. The fill character, if present, must be followed by an alignment flag. +The 'sign' option is only valid for numeric types, and can be one of the following: + +================= ==================================================== + Sign Meaning +================= ==================================================== +``+`` Indicates that a sign should be used for both + positive as well as negative numbers. +``-`` Indicates that a sign should be used only for + negative numbers (this is the default behavior). +`` `` (space) Indicates that a leading space should be used on + positive numbers. + If the '#' character is present, integers use the 'alternate form' for formatting. This means that binary, octal, and hexadecimal output will be prefixed with '0b', '0o', and '0x', respectively. @@ -273,6 +285,7 @@ macro fmt*(pattern: string): untyped = check fmt"{10}", "10" check fmt"{16:#X}", "0x10" check fmt"{16:^#7X}", " 0x10 " + check fmt"{16:^+#7X}", " +0x10 " # Hex tests check fmt"{0:x}", "0" @@ -292,6 +305,8 @@ macro fmt*(pattern: string): untyped = check fmt"{123.456}", "123.456" check fmt"{-123.456}", "-123.456" check fmt"{123.456:.3f}", "123.456" + check fmt"{123.456:+.3f}", "+123.456" + check fmt"{-123.456:+.3f}", "-123.456" check fmt"{-123.456:.3f}", "-123.456" check fmt"{123.456:1g}", "123.456" check fmt"{123.456:.1f}", "123.5" @@ -417,8 +432,7 @@ proc alignString*(s: string, minimumWidth: int; align = '<'; fill = ' '): string type StandardFormatSpecifier* = object ## Type that describes "standard format specifiers". fill*, align*: char ## Desired fill and alignment. - when false: - sign: char ## Desired sign. + sign*: char ## Desired sign. alternateForm*: bool ## Whether to prefix binary, octal and hex numbers ## with ``0b``, ``0o``, ``0x``. padWithZero*: bool ## Whether to pad with zeros rather than spaces. @@ -461,24 +475,23 @@ proc formatInt(n: SomeNumber; radix: int; spec: StandardFormatSpecifier): string result.add(mkDigit(d.int, spec.typ)) for idx in 0..<(result.len div 2): swap result[idx], result[result.len - idx - 1] - let adjustedWid = if negative: spec.minimumWidth - 1 else: spec.minimumWidth if spec.padWithZero: - let toFill = spec.minimumWidth - result.len - xx.len - ord(negative) + let sign = negative or spec.sign != '-' + let toFill = spec.minimumWidth - result.len - xx.len - ord(sign) if toFill > 0: result = repeat('0', toFill) & result + if negative: + result = "-" & xx & result + elif spec.sign != '-': + result = spec.sign & xx & result + else: + result = xx & result + if spec.align == '<': - if negative: - result = "-" & xx & result - else: - result = xx & result for i in result.len..<spec.minimumWidth: result.add(spec.fill) else: - if negative: - result = "-" & xx & result - else: - result = xx & result let toFill = spec.minimumWidth - result.len if spec.align == '^': let half = toFill div 2 @@ -492,7 +505,7 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; ## An exported helper proc that parses the "standard format specifiers", ## as specified by the grammar:: ## - ## [[fill]align][#][0][minimumwidth][.precision][type] + ## [[fill]align][sign][#][0][minimumwidth][.precision][type] ## ## This is only of interest if you want to write a custom ``format`` proc that ## should support the standard format specifiers. If ``ignoreUnknownSuffix`` is true, @@ -500,6 +513,7 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; const alignChars = {'<', '>', '^'} result.fill = ' ' result.align = '<' + result.sign = '-' var i = start if i + 1 < s.len and s[i+1] in alignChars: result.fill = s[i] @@ -509,11 +523,9 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; result.align = s[i] inc i - when false: - # XXX Python inspired 'sign' not yet supported! - if i < s.len and s[i] in {'-', '+', ' '}: - result.sign = s[i] - inc i + if i < s.len and s[i] in {'-', '+', ' '}: + result.sign = s[i] + inc i if i < s.len and s[i] == '#': result.alternateForm = true @@ -578,12 +590,11 @@ proc format*(value: SomeReal; specifier: string; res: var string) = "invalid type in format string for number, expected one " & " of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & spec.typ) - #let result = if spec.minimumWidth > 0 and spec.align == '<' and value < 0 and spec.padWithZero: - # "-" & alignString(formatBiggestFloat(-value, fmode, spec.precision), spec.minimumWidth-1, - # spec.align, '0') - #else: - let result = alignString(formatBiggestFloat(value, fmode, spec.precision), spec.minimumWidth, - spec.align, spec.fill) + var f = formatBiggestFloat(value, fmode, spec.precision) + if value >= 0.0 and spec.sign != '-': + f = spec.sign & f + let result = alignString(f, spec.minimumWidth, + spec.align, spec.fill) if spec.typ in {'A'..'Z'}: res.add toUpperAscii(result) else: |