diff options
Diffstat (limited to 'doc/format_specifications.rdoc')
-rw-r--r-- | doc/format_specifications.rdoc | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/doc/format_specifications.rdoc b/doc/format_specifications.rdoc new file mode 100644 index 0000000000..1111575e74 --- /dev/null +++ b/doc/format_specifications.rdoc @@ -0,0 +1,348 @@ += Format Specifications + +Several Ruby core classes have instance method +printf+ or +sprintf+: + +- ARGF#printf +- IO#printf +- Kernel#printf +- Kernel#sprintf + +Each of these methods takes: + +- Argument +format_string+, which has zero or more + embedded _format_ _specifications_ (see below). +- Arguments <tt>*arguments</tt>, which are zero or more objects to be formatted. + +Each of these methods prints or returns the string +resulting from replacing each +format specification embedded in +format_string+ with a string form +of the corresponding argument among +arguments+. + +A simple example: + + sprintf('Name: %s; value: %d', 'Foo', 0) # => "Name: Foo; value: 0" + +A format specification has the form: + + %[flags][width][.precision]type + +It consists of: + +- A leading percent character. +- Zero or more _flags_ (each is a character). +- An optional _width_ _specifier_ (an integer). +- An optional _precision_ _specifier_ (a period followed by a non-negative integer). +- A _type_ _specifier_ (a character). + +Except for the leading percent character, +the only required part is the type specifier, so we begin with that. + +== Type Specifiers + +This section provides a brief explanation of each type specifier. +The links lead to the details and examples. + +=== \Integer Type Specifiers + +- +b+ or +B+: Format +argument+ as a binary integer. + See {Specifiers b and B}[rdoc-ref:format_specifications.rdoc@Specifiers+b+and+B]. +- +d+, +i+, or +u+ (all are identical): + Format +argument+ as a decimal integer. + See {Specifier d}[rdoc-ref:format_specifications.rdoc@Specifier+d]. +- +o+: Format +argument+ as an octal integer. + See {Specifier o}[rdoc-ref:format_specifications.rdoc@Specifier+o]. +- +x+ or +X+: Format +argument+ as a hexadecimal integer. + See {Specifiers x and X}[rdoc-ref:format_specifications.rdoc@Specifiers+x+and+X]. + +=== Floating-Point Type Specifiers + +- +a+ or +A+: Format +argument+ as hexadecimal floating-point number. + See {Specifiers a and A}[rdoc-ref:format_specifications.rdoc@Specifiers+a+and+A]. +- +e+ or +E+: Format +argument+ in scientific notation. + See {Specifiers e and E}[rdoc-ref:format_specifications.rdoc@Specifiers+e+and+E]. +- +f+: Format +argument+ as a decimal floating-point number. + See {Specifier f}[rdoc-ref:format_specifications.rdoc@Specifier+f]. +- +g+ or +G+: Format +argument+ in a "general" format. + See {Specifiers g and G}[rdoc-ref:format_specifications.rdoc@Specifiers+g+and+G]. + +=== Other Type Specifiers + +- +c+: Format +argument+ as a character. + See {Specifier c}[rdoc-ref:format_specifications.rdoc@Specifier+c]. +- +p+: Format +argument+ as a string via <tt>argument.inspect</tt>. + See {Specifier p}[rdoc-ref:format_specifications.rdoc@Specifier+p]. +- +s+: Format +argument+ as a string via <tt>argument.to_s</tt>. + See {Specifier s}[rdoc-ref:format_specifications.rdoc@Specifier+s]. +- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character. + See {Specifier %}[rdoc-ref:format_specifications.rdoc@Specifier+-25]. + +== Flags + +The effect of a flag may vary greatly among type specifiers. +These remarks are general in nature. +See {type-specific details}[rdoc-ref:format_specifications.rdoc@Type+Specifier+Details+and+Examples]. + +Multiple flags may be given with single type specifier; +order does not matter. + +=== <tt>' '</tt> Flag + +Insert a space before a non-negative number: + + sprintf('%d', 10) # => "10" + sprintf('% d', 10) # => " 10" + +Insert a minus sign for negative value: + + sprintf('%d', -10) # => "-10" + sprintf('% d', -10) # => "-10" + +=== <tt>'#'</tt> Flag + +Use an alternate format; varies among types: + + sprintf('%x', 100) # => "64" + sprintf('%#x', 100) # => "0x64" + +=== <tt>'+'</tt> Flag + +Add a leading plus sign for a non-negative number: + + sprintf('%x', 100) # => "64" + sprintf('%+x', 100) # => "+64" + +=== <tt>'-'</tt> Flag + +Left justify the value in its field: + + sprintf('%6d', 100) # => " 100" + sprintf('%-6d', 100) # => "100 " + +=== <tt>'0'</tt> Flag + +Left-pad with zeros instead of spaces: + + sprintf('%6d', 100) # => " 100" + sprintf('%06d', 100) # => "000100" + +=== <tt>'*'</tt> Flag + +Use the next argument as the field width: + + sprintf('%d', 20, 14) # => "20" + sprintf('%*d', 20, 14) # => " 14" + +=== <tt>'n$'</tt> Flag + +Format the (1-based) <tt>n</tt>th argument into this field: + + sprintf("%s %s", 'world', 'hello') # => "world hello" + sprintf("%2$s %1$s", 'world', 'hello') # => "hello world" + +== Width Specifier + +In general, a width specifier determines the minimum width (in characters) +of the formatted field: + + sprintf('%10d', 100) # => " 100" + + # Left-justify if negative. + sprintf('%-10d', 100) # => "100 " + + # Ignore if too small. + sprintf('%1d', 100) # => "100" + +== Precision Specifier + +A precision specifier is a decimal point followed by zero or more +decimal digits. + +For integer type specifiers, the precision specifies the minimum number of +digits to be written. If the precision is shorter than the integer, the result is +padded with leading zeros. There is no modification or truncation of the result +if the integer is longer than the precision: + + sprintf('%.3d', 1) # => "001" + sprintf('%.3d', 1000) # => "1000" + + # If the precision is 0 and the value is 0, nothing is written + sprintf('%.d', 0) # => "" + sprintf('%.0d', 0) # => "" + +For the +a+/+A+, +e+/+E+, +f+/+F+ specifiers, the precision specifies +the number of digits after the decimal point to be written: + + sprintf('%.2f', 3.14159) # => "3.14" + sprintf('%.10f', 3.14159) # => "3.1415900000" + + # With no precision specifier, defaults to 6-digit precision. + sprintf('%f', 3.14159) # => "3.141590" + +For the +g+/+G+ specifiers, the precision specifies +the number of significant digits to be written: + + sprintf('%.2g', 123.45) # => "1.2e+02" + sprintf('%.3g', 123.45) # => "123" + sprintf('%.10g', 123.45) # => "123.45" + + # With no precision specifier, defaults to 6 significant digits. + sprintf('%g', 123.456789) # => "123.457" + +For the +s+, +p+ specifiers, the precision specifies +the number of characters to write: + + sprintf('%s', Time.now) # => "2022-05-04 11:59:16 -0400" + sprintf('%.10s', Time.now) # => "2022-05-04" + +== Type Specifier Details and Examples + +=== Specifiers +a+ and +A+ + +Format +argument+ as hexadecimal floating-point number: + + sprintf('%a', 3.14159) # => "0x1.921f9f01b866ep+1" + sprintf('%a', -3.14159) # => "-0x1.921f9f01b866ep+1" + sprintf('%a', 4096) # => "0x1p+12" + sprintf('%a', -4096) # => "-0x1p+12" + + # Capital 'A' means that alphabetical characters are printed in upper case. + sprintf('%A', 4096) # => "0X1P+12" + sprintf('%A', -4096) # => "-0X1P+12" + +=== Specifiers +b+ and +B+ + +The two specifiers +b+ and +B+ behave identically +except when flag <tt>'#'</tt>+ is used. + +Format +argument+ as a binary integer: + + sprintf('%b', 1) # => "1" + sprintf('%b', 4) # => "100" + + # Prefix '..' for negative value. + sprintf('%b', -4) # => "..100" + + # Alternate format. + sprintf('%#b', 4) # => "0b100" + sprintf('%#B', 4) # => "0B100" + +=== Specifier +c+ + +Format +argument+ as a single character: + + sprintf('%c', 'A') # => "A" + sprintf('%c', 65) # => "A" + +=== Specifier +d+ + +Format +argument+ as a decimal integer: + + sprintf('%d', 100) # => "100" + sprintf('%d', -100) # => "-100" + +Flag <tt>'#'</tt> does not apply. + +=== Specifiers +e+ and +E+ + +Format +argument+ in +{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]: + + sprintf('%e', 3.14159) # => "3.141590e+00" + sprintf('%E', -3.14159) # => "-3.141590E+00" + +=== Specifier +f+ + +Format +argument+ as a floating-point number: + + sprintf('%f', 3.14159) # => "3.141590" + sprintf('%f', -3.14159) # => "-3.141590" + +Flag <tt>'#'</tt> does not apply. + +=== Specifiers +g+ and +G+ + +Format +argument+ using exponential form (+e+/+E+ specifier) +if the exponent is less than -4 or greater than or equal to the precision. +Otherwise format +argument+ using floating-point form (+f+ specifier): + + sprintf('%g', 100) # => "100" + sprintf('%g', 100.0) # => "100" + sprintf('%g', 3.14159) # => "3.14159" + sprintf('%g', 100000000000) # => "1e+11" + sprintf('%g', 0.000000000001) # => "1e-12" + + # Capital 'G' means use capital 'E'. + sprintf('%G', 100000000000) # => "1E+11" + sprintf('%G', 0.000000000001) # => "1E-12" + + # Alternate format. + sprintf('%#g', 100000000000) # => "1.00000e+11" + sprintf('%#g', 0.000000000001) # => "1.00000e-12" + sprintf('%#G', 100000000000) # => "1.00000E+11" + sprintf('%#G', 0.000000000001) # => "1.00000E-12" + +=== Specifier +o+ + +Format +argument+ as an octal integer. +If +argument+ is negative, it will be formatted as a two's complement +prefixed with +..7+: + + sprintf('%o', 16) # => "20" + + # Prefix '..7' for negative value. + sprintf('%o', -16) # => "..760" + + # Prefix zero for alternate format if positive. + sprintf('%#o', 16) # => "020" + sprintf('%#o', -16) # => "..760" + +=== Specifier +p+ + +Format +argument+ as a string via <tt>argument.inspect</tt>: + + t = Time.now + sprintf('%p', t) # => "2022-05-01 13:42:07.1645683 -0500" + +=== Specifier +s+ + +Format +argument+ as a string via <tt>argument.to_s</tt>: + + t = Time.now + sprintf('%s', t) # => "2022-05-01 13:42:07 -0500" + +Flag <tt>'#'</tt> does not apply. + +=== Specifiers +x+ and +X+ + +Format +argument+ as a hexadecimal integer. +If +argument+ is negative, it will be formatted as a two's complement +prefixed with +..f+: + + sprintf('%x', 100) # => "64" + + # Prefix '..f' for negative value. + sprintf('%x', -100) # => "..f9c" + + # Use alternate format. + sprintf('%#x', 100) # => "0x64" + + # Alternate format for negative value. + sprintf('%#x', -100) # => "0x..f9c" + +=== Specifier <tt>%</tt> + +Format +argument+ (<tt>'%'</tt>) as a single percent character: + + sprintf('%d %%', 100) # => "100 %" + +Flags do not apply. + +== Reference by Name + +For more complex formatting, Ruby supports a reference by name. +%<name>s style uses format style, but %{name} style doesn't. + +Examples: + + sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) # => 1 : 2.000000 + sprintf("%{foo}f", { :foo => 1 }) # => "1f" |