%a %A %b %B %c %d %e %E %f %g %G %i %o %p %s %u %x %X %% 0 $ # + - * space

Ruby comes with a structured alternative to classic string interpolation: This episode will explore format strings, also known as the sprintf syntax.

Recall the normal way of interpolating variables into a string:

v = 42 "--> #{v} <--" # => "--> 42 <--"

Format strings are different in that they use a string template and bind it to data via the % method:¹

v = 42 "--> %s <--" % v # => "--> 42 <--"

This might look familiar to you, because dozens of other programming languages also support some flavor of this syntax.

¹ Some people prefer the functional-style Kernel#sprintf or Kernel#format methods, which let you access the same functionality

Four Kinds of References

Format strings separate the string's format (= template) from the actual data. The template contains references in the format of %X (unnamed) or %<name>X (named). The X consists of the formatting type, optionally preceded by other formatting options (see next section). The most basic formatting type is %s , which stands for string. You cannot mix between the two referencing styles; either go with named or unnamed:

# Named format strings take a hash parameter: "--> %<forty_two>s -- %<forty_three>s <--" % {forty_two: 42, forty_three: 43} # => --> 42 -- 43 <-- # Named format strings, fancy style (note the dot before `%`): "--> %<forty_two>s -- %<forty_three>s <--".% forty_two: 42, forty_three: 43 # => --> 42 -- 43 <-- # Shorter, simple/unnamed format strings, take an array as parameter: "--> %s -- %s <--" % [42, 43] # => --> 42 -- 43 <-- # If you only need to interpolate a single value, you can shorten this to: "--> %s <--" % 42 # => --> 42 <-- # Attempt to mix: "--> %s -- %<second>s <--" % [1, second: 2] # ArgumentError: named<second> after unnumbered(1)

Conceptionally, this is very similar to how regular expressions handle references. For simple interpolations use simple references, for more complex interpolations named references might be a better fit. Named references serve as inline documentation.

Referencing: Template Style

Besides the two main styles, there exists a shorthand syntax for using format strings with named references:

"--> %{first} -- %{second} <--".% first: 1, second: 2 # => --> 1 -- 2 <--

Though you will use the ability to apply a formatting type (see below), it is concise and looks good. At its core, it is templating built into the language!

Referencing: Absolute Positioning

The fourth way of referencing the values is the most unreadable one and I would not recommend it. It is a modification of the unnamed reference style: Instead of using the variables in the order you passed them in, you denote the position of the value in the template string using n$ :

"--> %2$s -- %1$s <--" % [:first, :second] # => "--> second -- first <--"

Again, mixing with other types of referencing will lead to errors like this one:

"--> %2$s -- %s <--" % [:first, :second] # ArgumentError: unnumbered(1) mixed with numbered

Flags, Widths, and Formatting Type

In the previous examples, only basic string substitution was used. But format strings can do more: They can convert a value to another representation using a different formatting type. The formatting type is specified by the last letter of the reference. Besides %s , another common used formatting type is %d , which will put the value through Interger() :

"%d" % 1 # => 1 "%d" % "1" # => 1 "%d" % "string without integer value" # ArgumentError: invalid value for Integer(): "string without integer value"

There are three different kinds of formatting types: Format as String , format as Integer , and format as Float . See further below for a detailed description. Often, the formatting can be enhanced with special flags or widths. Special options appear between the % sign and the formatting type². For example:

"%.2f" % 1.23456 # => 1.23

This is a float conversion, and the special option "precision of 2" was used. Different formatting types support different kinds of flags and options. The complete syntax of a reference is:

%<name>AB.CX

Syntax Notes Required/Optional % -³ Required <name> Named reference Optional A Flags Optional B Width Optional . C Precision Optional X Formatting type Required

² As fnordfish noted, the syntax can sometimes be quite confusing, such as in:

"Such %<num> cookies" % { num: 100 }

³ Since the % character denotes a reference, you have to use %% to get a single "%"

What follows is a description of all formatting options and types.

Formatting Flags and Options: String Padding

When the format string parser finds a number (which is not a preceded by . or $ ), it will treat the value as a padding width. The padding width defines the minimum string length, the remaining space will be filled with ASCII spaces. This is a similar functionality like provided by String#ljust:

"%20s" % "Idiosyncratic" # => " Idiosyncratic"

It also works with template-style references:

"%20{ruby}".% ruby: "Idiosyncratic" #=> " Idiosyncratic"

- | Minus

You can use "negative widths" to right-pad a string:

"%-20s" % "Idiosyncratic" # => "Idiosyncratic "

* | Star

A dynamic padding width can be achieved with * . This will require two arguments and does not work with named references:

w = 20 "%*s" % [w, "Idiosyncratic"] # => " Idiosyncratic"

Note: Alternatively, you can just inline-interpolate the format string:

w = 20 "%#{w}s" % "Idiosyncratic" # => " Idiosyncratic"

Can be combined with absolute positioned references (e.g. "%1$*2$s" ).

0 | Zero

The 0 as flag allows you to pad numerical values with zeros instead of spaces:

"%020i" % 1 # => #=> "00000000000000000001"

Will not work for %s , %p , or %c . Can also not be combined with the - flag (right-pad).

Formatting Flags and Options: Algebraic Sign

+ | Plus

The + flag forces a "+" sign for positive numbers:

"%+d" % 1 # => "+1" "%+d" % -1 # => "-1"

Will not work for %s , %p , or %c .

⍽ | Space

In a similar manner, the flag, forces positive numbers to leave a space (for a potential "-" sign):

"% d" % 1 # => " 1" "% d" % -1 # => "-1"

Will not work for %s , %p , or %c .

Other Formatting Flags and Options

# | Hash

Modifies the way a numerical value gets converted. What it exactly does varies, so see the description at respective formatting type!

Formatting Types: String

%s | String

Does nothing but putting the string argument at the right position.

"%s Ruby" % "Idiosyncratic" # => "Idiosyncratic Ruby"

Will call to_s on the object passed in.

"%s Ruby" % :Idiosyncratic # => "Idiosyncratic Ruby"

A padding example:

"%4s" % "A" # => " A"

Using the precision syntax, you can pass a hard length limit:

"%.4s" % "Idiosyncratic" # => "Idio"

Padding + Limit:

"%4.8s" % "12" # => " 12" "%4.8s" % "1234567890" # => "12345678"

%p | Inspect

Calls inspect on the value:

"%p" % "Idiosyncratic" # => "\"Idiosyncratic\""

Supports the same flags and arguments like %s .

%c | Character

Interpretes a numerical value as a codepoint of the current encoding and converts it to the respective character (the reverse of String#ord, similar to what Array#pack("U") does for UTF-8 strings):

"%c" % 11835 # => "⸻"

Can also be used with a single letter string, which will just be inserted (as if was used with %s ):

"%c" % "A" # => "A"

Formatting Types: Integer

A padding width has the same effect it has for strings. When Integer formatting is used together with a precision it will act as the minimum number of digits to display (which is different from the effect it has in Float formatting):

"%6.4d" % 20 # => " 0020"

The all integer formatting type will run the value through Integer() :

"%d" % 42.9 # => "42" "%d" % "23" # => "23" "%d" % "0xff" # => "255" "%d" % nil # TypeError: can't convert nil into Integer

%d, %i, %u | Integer (Decimal Number)

%d , %i and %u all convert the value to an integer (see explanation above):

"%d" % "123" # => 123

%b, %B | Binary Number

Converts the number to a binary number string:

"%b" % 42 # => "101010"

Note: Another way of achieving the same would be to use Numeric#to_s(2):

42.to_s(2) # => "101010"

Negative numbers will be convert to two's complement, preceded by "..1" representing an infinite string of leading "1"s:

"%b" % -42 # => "..1010110"

This is not the case when the + or flag are in use:

"%+b" % -42 # => "-101010"

Alternative conversion format ( # flag) will prepend "0b" (except for 0):

"%#b" % 42 # => "0b101010"

The %B type has exactly the same behavior as %b , except that it will use an uppercase "B" in alternative conversion format:

"%#B" % 42 # => "0B101010"

%o | Octal Number

Converts the number to an octal number string:

"%o" % 42 # => "52"

Note: Another way of achieving the same would be to use Numeric#to_s(8):

42.to_s(8) # => "52"

Negative numbers will be convert to two's complement, preceded by "..7" representing an infinite string of leading "7"s:

"%o" % -42 # => "..726"

This is not the case when the + or flag are in use:

"%+o" % -42 # => "-52"

Alternative conversion format ( # flag) will prepend "0" (except for 0):

"%#o" % 42 # => "052"

%x, %X | Hexadecimal Number

Converts the number to a hexadecimal number string:

"%x" % 42 # => "2a"

The %X type has the same behavior, except that it will used uppercased letters:

"%X" % 42 # => "2A"

Note: Another way of achieving the same would be to use Numeric#to_s(16):

42.to_s(16) # => "2a"

Negative numbers will be convert to two's complement, preceded by "..f" representing an infinite string of leading "f"s:

"%x" % -42 # => "..fd6"

This is not the case when the + or flag are in use:

"%+x" % -42 # => "-2a"

Alternative conversion format ( # flag) will prepend "0x" (except for 0):

"%#x" % 42 # => "0x2a"

Or "0X" when using big %X :

"%#X" % 42 # => "0X2A"

Formatting Types: Float

%f | Float

This will convert the argument to a floating point number:

"%f" % 42 # => "42.000000"

The precision syntax defines the actual precision here:

"%.2f" % 42 # => "42.00" "%.3f" % 42 # => "42.000"

%e, %E | Float in Exponential Notation

Converts the value to a float in exponential notation (with 6 digits before the exponent):

"%e" % 42 # => "4.200000e+01" "%e" % 0.00000023 # => "2.300000e-07" "%e" % -1_000_000_000 # => "-1.000000e+09"

The precision syntax defines the number of digits before the exponent:

"%.2e" % 42 #=> "4.20e+01" "%.4e" % 42 # => "4.2000e+01"

Using big %E will uppercase the "E" in the result:

"%E" % 1 # => "1.000000E+00"

%g, %G | Float in Normal or Exponential Notation

Converts a float either to normal representation 1.23 or exponential notation (see %e above). Which one is chosen, depends on the number: If the exponent is more than 5 or less than -4, exponential format is used:

>> "%g" % 100000 # => "100000" >> "%g" % 1000000 # => "1e+06" >> "%g" % 0.0001 # => "0.0001" >> "%g" % 0.00001 # => "1e-05"

Will use a given (positive) precision as the point to decide between both notation forms:

"%.2g" % 10 # => "10" "%.2g" % 100 # => "1e+02"

Using big %G will uppercase the "E" in the result:

"%G" % 1234567890 # => "1.23457E+09"

%a, %A | Analyze Float

Converts a float into a format revealing its underlying representation, which is divided into significant (mantissa) and exponent. The result is a string of the following format:

- (if negative) + 0x + significant (hexadecimal) + p + exponent sign + exponent (decimal)

Examples:

"%a" % 1 # => "0x1p+0" "%a" % 1.2 # => "0x1.3333333333333p+0" "%a" % 1.23 # => "0x1.3ae147ae147aep+0" "%a" % 0.1 # => "0x1.999999999999ap-4" "%a" % 10000000000 # => "0x1.2a05f2p+33" "%a" % 0.000000001 # => "0x1.12e0be826d695p-30"

Using big %A will uppercase all letters:

"%A" % -12.34 # => "-0X1.8AE147AE147AEP+3"

Classic Interpolation vs. Format Strings

Advantages of Format Strings

Values sit side by side, instead of being all around the place

Simple access to string padding functionality

Advanced (and explicit) numerical conversions

Can be used as built-in mini templating engine

Advantages of Classical Interpolation

Interpolation happens on syntax level, no method calling involved

Inline interpolation quicker to write/more convenient for simple interpolations

Not possible to mismatch values and format string references

Resources

Also See

More Idiosyncratic Ruby