From 45a3d25cf2ce76e62cfca1e1e18dba1e023a173f Mon Sep 17 00:00:00 2001 From: r00ster Date: Sat, 15 Sep 2018 11:15:54 +0200 Subject: [PATCH 1/4] Improve sprintf docs, minor String::Formatter refactors --- src/kernel.cr | 119 ++++++++++++++++++++-------------------- src/string/formatter.cr | 22 +++++--- 2 files changed, 73 insertions(+), 68 deletions(-) diff --git a/src/kernel.cr b/src/kernel.cr index 3867b9a32227..45da5bb89521 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -73,7 +73,7 @@ end # The syntax for a format specifier is: # # ```text -# %[flags][width][.precision]type +# %[flags][width][.precision][type] # ``` # # A format specifier consists of a percent sign, followed by optional flags, @@ -87,70 +87,67 @@ end # The field type characters are: # # ```text -# Field | Integer Format -# ------+-------------------------------------------------------------- -# b | Formats argument as a binary number. -# d | Formats argument as a decimal number. -# i | Same as d. -# o | Formats argument as an octal number. -# x | Formats argument as a hexadecimal number using lowercase letters. -# X | Same as x, but uses uppercase letters. -# -# Field | Float Format -# ------+-------------------------------------------------------------- -# e | Formats floating point argument into exponential notation -# | with one digit before the decimal point as [-]d.dddddde[+-]dd. -# | The precision specifies the number of digits after the decimal -# | point (defaulting to six). -# E | Equivalent to e, but uses an uppercase E to indicate -# | the exponent. -# f | Formats floating point argument as [-]ddd.dddddd, -# | where the precision specifies the number of digits after -# | the decimal point. -# g | Formats a floating point number using exponential form -# | if the exponent is less than -4 or greater than or -# | equal to the precision, or in dd.dddd form otherwise. -# | The precision specifies the number of significant digits. -# G | Equivalent to g, but use an uppercase E in exponent form. -# a | Formats floating point argument as [-]0xh.hhhhp[+-]dd, -# | which is consisted from optional sign, "0x", fraction part -# | as hexadecimal, "p", and exponential part as decimal. -# A | Equivalent to a, but use uppercase X and P. -# -# Field | Other Format -# ------+-------------------------------------------------------------- -# c | Argument is the numeric code for a single character or -# | a single character string itself. -# s | Argument is a string to be substituted. If the format -# | sequence contains a precision, at most that many characters -# | will be copied. -# % | A percent sign itself will be displayed. No argument taken. -# +# Field | Integer Format +# ------+------------------------------------------------------------------ +# b | Formats argument as a binary number. +# d | Formats argument as a decimal number. +# i | Same as d. +# o | Formats argument as an octal number. +# x | Formats argument as a hexadecimal number using lowercase letters. +# X | Same as x, but uses uppercase letters. +# +# Field | Float Format +# ------+--------------------------------------------------------------- +# e | Formats floating point argument into exponential notation +# | with one digit before the decimal point as [-]d.dddddde[+-]dd. +# | The precision specifies the number of digits after the decimal +# | point (defaulting to six). +# E | Equivalent to e, but uses an uppercase E to indicate +# | the exponent. +# f | Formats floating point argument as [-]ddd.dddddd, +# | where the precision specifies the number of digits after +# | the decimal point. +# g | Formats a floating point number using exponential form +# | if the exponent is less than -4 or greater than or +# | equal to the precision, or in dd.dddd form otherwise. +# | The precision specifies the number of significant digits. +# G | Equivalent to g, but use an uppercase E in exponent form. +# a | Formats floating point argument as [-]0xh.hhhhp[+-]dd, +# | which is consisted from optional sign, "0x", fraction part +# | as hexadecimal, "p", and exponential part as decimal. +# A | Equivalent to a, but use uppercase X and P. +# +# Field | Other Format +# ------+------------------------------------------------------------ +# c | Argument is a single character itself. +# s | Argument is a string to be substituted. If the format +# | sequence contains a precision, at most that many characters +# | will be copied. +# % | A percent sign itself will be displayed. No argument taken. # ``` # The flags modifies the behavior of the formats. # The flag characters are: # ```text -# -# Flag | Applies to | Meaning -# ---------+---------------+----------------------------------------- -# space | bdiouxX | Add a leading space character to -# | aAeEfgG | non-negative numbers. -# | (numeric fmt) | For o, x, X, b, use -# | | a minus sign with absolute value for -# | | negative values. -# ---------+---------------+----------------------------------------- -# + | bdiouxX | Add a leading plus sign to non-negative -# | aAeEfgG | numbers. -# | (numeric fmt) | For o, x, X, b, use -# | | a minus sign with absolute value for -# | | negative values. -# ---------+---------------+----------------------------------------- -# - | all | Left-justify the result of this conversion. -# ---------+---------------+----------------------------------------- -# 0 (zero) | bdiouxX | Pad with zeros, not spaces. -# | aAeEfgG | For o, x, X, b, radix-1 -# | (numeric fmt) | is used for negative numbers formatted as -# | | complements. +# Flag | Applies to | Meaning +# ---------+---------------+-------------------------------------------- +# space | bdiouxX | Add a leading space character to +# | aAeEfgG | non-negative numbers. +# | (numeric fmt) | For o, x, X, b, use +# | | a minus sign with absolute value for +# | | negative values. +# ---------+---------------+-------------------------------------------- +# + | bdiouxX | Add a leading plus sign to non-negative +# | aAeEfgG | numbers. +# | (numeric fmt) | For o, x, X, b, use +# | | a minus sign with absolute value for +# | | negative values. +# ---------+---------------+-------------------------------------------- +# - | all | Left-justify the result of this conversion. +# ---------+---------------+-------------------------------------------- +# 0 (zero) | bdiouxX | Pad with zeros, not spaces. +# | aAeEfgG | For o, x, X, b, radix-1 +# | (numeric fmt) | is used for negative numbers formatted as +# | | complements. # ``` # # Examples of flags: diff --git a/src/string/formatter.cr b/src/string/formatter.cr index 07e846d52569..ef03e81546ec 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -92,8 +92,6 @@ struct String::Formatter(A) case current_char when ' ' flags.space = true - when '#' - flags.sharp = true when '+' flags.plus = true when '-' @@ -110,7 +108,7 @@ struct String::Formatter(A) private def consume_width(flags) case current_char - when '1'..'9' + when '0'..'9' num, size = consume_number flags.width = num flags.width_size = size @@ -125,7 +123,7 @@ struct String::Formatter(A) private def consume_precision(flags) if current_char == '.' case next_char - when '1'..'9' + when '0'..'9' num, size = consume_number flags.precision = num flags.precision_size = size @@ -172,6 +170,8 @@ struct String::Formatter(A) private def consume_type(flags, arg = nil, arg_specified = false) case char = current_char + when 'c' + char flags, arg, arg_specified when 's' string flags, arg, arg_specified when 'b' @@ -197,6 +197,14 @@ struct String::Formatter(A) end end + def char(flags, arg, arg_specified) + arg = next_arg unless arg_specified + + pad 1, flags if flags.left_padding? + @io << arg + pad 1, flags if flags.right_padding? + end + def string(flags, arg, arg_specified) arg = next_arg unless arg_specified @@ -241,7 +249,7 @@ struct String::Formatter(A) end end - # We don't actually format the float ourselves, we delegate to sprintf + # We don't actually format the float ourselves, we delegate to snprintf def float(flags, arg, arg_specified) arg = next_arg unless arg_specified @@ -352,12 +360,12 @@ struct String::Formatter(A) end struct Flags - property space : Bool, sharp : Bool, plus : Bool, minus : Bool, zero : Bool, base : Int32 + property space : Bool, plus : Bool, minus : Bool, zero : Bool, base : Int32 property width : Int32, width_size : Int32 property type : Char, precision : Int32?, precision_size : Int32 def initialize - @space = @sharp = @plus = @minus = @zero = false + @space = @plus = @minus = @zero = false @width = 0 @width_size = 0 @base = 10 From 39c2aedc12ecc0ce01b2d5393d53db69e2188105 Mon Sep 17 00:00:00 2001 From: r00ster Date: Thu, 20 Sep 2018 22:26:04 +0200 Subject: [PATCH 2/4] Add sharp to recreate_float_format_string --- src/string/formatter.cr | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/string/formatter.cr b/src/string/formatter.cr index ef03e81546ec..616662218d1d 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -92,6 +92,8 @@ struct String::Formatter(A) case current_char when ' ' flags.space = true + when '#' + flags.sharp = true when '+' flags.plus = true when '-' @@ -283,6 +285,7 @@ struct String::Formatter(A) io = IO::Memory.new(Bytes.new(format_buf, capacity)) io << '%' + io << '#' if flags.sharp io << '+' if flags.plus io << '-' if flags.minus io << '0' if flags.zero @@ -360,12 +363,12 @@ struct String::Formatter(A) end struct Flags - property space : Bool, plus : Bool, minus : Bool, zero : Bool, base : Int32 + property space : Bool, sharp : Bool, plus : Bool, minus : Bool, zero : Bool, base : Int32 property width : Int32, width_size : Int32 property type : Char, precision : Int32?, precision_size : Int32 def initialize - @space = @plus = @minus = @zero = false + @space = @sharp = @plus = @minus = @zero = false @width = 0 @width_size = 0 @base = 10 From 2c537d1e2352d02e083ca3ae3013c2a132a9a75e Mon Sep 17 00:00:00 2001 From: r00ster <35064754+r00ster91@users.noreply.github.com> Date: Thu, 20 Sep 2018 23:05:27 +0200 Subject: [PATCH 3/4] Remove 2 brackets --- src/kernel.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel.cr b/src/kernel.cr index 45da5bb89521..3120b59ce24c 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -73,7 +73,7 @@ end # The syntax for a format specifier is: # # ```text -# %[flags][width][.precision][type] +# %[flags][width][.precision]type # ``` # # A format specifier consists of a percent sign, followed by optional flags, From bdd9f63beca5009ee6cbded45adc13a971fd46e6 Mon Sep 17 00:00:00 2001 From: r00ster <35064754+r00ster91@users.noreply.github.com> Date: Wed, 10 Oct 2018 20:12:14 +0200 Subject: [PATCH 4/4] '0'..'9' ->'1'..'9' --- src/string/formatter.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/string/formatter.cr b/src/string/formatter.cr index 616662218d1d..d14ddf88ed6f 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -110,7 +110,7 @@ struct String::Formatter(A) private def consume_width(flags) case current_char - when '0'..'9' + when '1'..'9' num, size = consume_number flags.width = num flags.width_size = size @@ -125,7 +125,7 @@ struct String::Formatter(A) private def consume_precision(flags) if current_char == '.' case next_char - when '0'..'9' + when '1'..'9' num, size = consume_number flags.precision = num flags.precision_size = size