FormattedIO

Usage

use IO.FormattedIO;

or

import IO.FormattedIO;

Support for formatted input and output.

Formatted I/O

See below for a sample-based overview of the format strings. Further below, we describes the format string syntax in detail. Finally, we demonstrate the functionality with example function calls.

Overview of Format Strings

In a manner similar to C’s ‘printf’ and ‘scanf’, the IO package includes fileWriter.writef and fileReader.readf functions. These functions take in a format string and some arguments. The string.format method is also available and is loosely equivalent to C’s ‘sprintf’. For example, one might do:

writef("My favorite %s is %i\n", "number", 7);

var s:string = "My favorite %s is %i".format("number", 7);
writeln(s);

// prints:
// My favorite number is 7
// My favorite number is 7

The following sections offer a tour through the conversions to illustrate the common cases. A more precise definition follows in the Format String Syntax in Detail section below.

In this file, we use “integral” to refer to the Chapel types int or uint and “floating-point” to refer to real, imaginary, or complex, of any bit width.

Formatted I/O for C Programmers

This table is designed to help C programmers understand the equivalent Chapel format specifiers.

C

Chapel

Meaning

%i

%i

a signed integer in decimal

%d

%i

a signed integer in decimal

%u

%u

an unsigned integer in decimal

%x

%xu

an unsigned integer in hexadecimal

%g

%r

real number in exponential or decimal (if compact)

%7.2g

%7.2r

real, 2 significant digits, padded to 7 columns

%f

%dr

real number always in decimal

%7.3f

%7.3dr

real, 3 digits after ., padded to 7 columns

%e

%er

real number always in exponential

%7.3e

%7.3er

real, 3 digits after ., padded to 7 columns

%s

%s

a string without any quoting

Unlike in C, a value of the wrong type will be cast appropriately - so for example printing 2 (an int) with %.2dr will result in 2.00. Note that Chapel’s %n and %? are equivalent to %r for real conversions and %i for numeric conversions; so these are also equivalent to %i %d or %g in C. Also note that Chapel format strings include many capabilities not available with C formatted I/O routines - including quoted strings, binary numbers, and complex numbers.

Generic Numeric Conversions

%{##.###}

decimal number padded on the left with spaces to 2 digits before the point, rounded to 3 after. Works with integral, real, imaginary, or complex arguments.

In all cases, the output is padded on the left to the total length of the conversion specifier (6 in this example). The output can be longer, when needed to accommodate the number.

%{#####}

integral value padded out to 5 digits. Also works with real, imaginary or complex numbers by rounding them to integers. Numbers with more digits will take up more space instead of being truncated.

In both conversions above, an imaginary argument gets an ‘i’ afterwards and the entire expression is padded out to the width of ##### digits. For example:

writef("|%{#####}|\n", 2.0i);
     // outputs:
     //   |   2i|

writef("|%{#####.#}|\n", 2.0i);
     // outputs:
     //   |   2.0i|

Complex arguments are printed in the format a + bi, where each of a and b is rounded individually as if printed under that conversion on its own. Then, the formatted complex number is padded to the requested size. For example:

writef("|%{#########}|\n", 1.0+2.0i);
     // outputs:
     //   |   1 + 2i|

writef("|%{#########.#}|\n", 1.0+2.0i);
     // outputs:
     //   | 1.0 + 2.0i|

See # Specifiers for more details on this conversion type.

%n

a “number” - equivalent to one of %i, %u, %r, %m, or %z below, depending on the type

%17n

a number padded out to 17 columns

%.4n

a number with 4 significant digits or a precision of 4

Integral Conversions

%i or %di

a signed integer in decimal, possibly negative (note - when reading an %i, - is allowed)

%u or %du

an unsigned decimal integer (note - when reading a %u, - is not allowed)

%bi

a binary signed integer

%bu

a binary unsigned integer

%@bu

a binary unsigned integer prefixed with 0b

%oi

an octal signed integer

%ou

an octal unsigned integer

%@ou

an octal unsigned integer prefixed with 0o

%xu

a hexadecimal unsigned integer

%xi

a hexadecimal signed integer

%@xu

a hexadecimal unsigned integer prefixed with 0x

%Xu

a hexadecimal unsigned integer in uppercase

%@Xu

a hexadecimal unsigned integer prefixed with 0X and uppercase

%17i

a decimal integer padded on the left with spaces to 17 columns (That is, it is right-justified in a 17-column field. Padding width is ignored when reading integers)

%*i

as with %17i but read the minimum width from the preceding argument

%017i

a decimal integer padded on the left with zeros to 17 columns

%<17i

a decimal integer left-justified (padded on the right) to 17 columns

%^17i

a decimal integer center-justified (padded equally on the left and right) to 17 columns

%>17i

a decimal integer right-justified (padded on the left) to 17 columns — equivalent to %17i

%+i

a decimal integer showing + for positive numbers

% i

a decimal integer with a space for positive numbers

Real Conversions

%r

a real number with decimal or exponential notation, where exponential is chosen if the decimal version would be too long

%6r

as with %r but padded on the left to 6 columns (i.e., right-justified)

%<6r

as with %r but padded on the right to 6 columns (i.e., left-justified)

%^6r

as with %r but padded equally on the left and right to 6 columns (i.e., center-justified)

%>6r

equivalent to %6r

%.4r

as with %r but with 4 significant digits

%.*r

as with %.4r but with significant digits read from preceding argument

%6.4r

as with %r but padded on the left to 6 columns and with 4 significant digits

%*.*r

as with %6.4r but read minimum width and significant digits from preceding arguments

%dr

a real number in decimal notation, e.g. 12.34

%6dr

a decimal number padded on the left to 6 columns (right-justified)

%.4dr

a decimal number with 4 digits after the radix point

%6.4dr

a decimal number padded on the left to 6 columns and with 4 digits after the radix point (width and precision are ignored when reading numbers in readf)

%er

a real number in exponential notation, e.g. 8.2e-23

%Er

like %er but with the ‘e’ in uppercase, e.g. 8.2E-23

%.4er

exponential notation with 4 digits after the period, e.g. 8.2000e-23

%xer

hexadecimal number using p to mark exponent e.g. 6c.3f7p-2a

Complex and Imaginary Conversions

%m

an imaginary number, like a real with %r but ends with an i

%z

print complex number with %r for each part in the format a + bi

%@z

print complex number with %r for each part in the format (a,b)

%6z

as with %z but pad the entire complex number out to 6 columns

%6.4z

print a and b 4 significant digits and pad the entire complex number out to 6 columns

%dz

print a and b with %dr (using decimal notation)

%ez

print a and b with %er (using exponential notation)

String and Bytes Conversions

%s

a string. When reading, read until whitespace. Note that if you want to be able to read your string back in, you should use one of the quoted or encoded binary versions (see below), since generally with %s it’s not clear where the string ends.

%c

a single Unicode character (argument should be a string or an integral storing the character code)

%17s
  • when writing - a string left padded (right justified) to 17 columns

  • when reading - read up to 17 bytes or a whitespace, whichever comes first, rounding down to whole characters

%<17s
  • when writing - a string right padded (left justified) to 17 columns

%^17s
  • when writing - a string equally left and right padded (center justified) to 17 columns

%>17s
  • when writing - a string left padded (right justified) to 17 columns

  • when reading - read up to 17 bytes or a whitespace, whichever comes first, rounding down to whole characters

%.17s
  • when writing - a string truncated to 17 columns. When combined with quoting strings, for example %.17"S, the conversion will print … after a string if it was truncated. The truncation includes leaving room for the quotes and - if needed - the periods, so the shortest truncated string is ""... Generally, you won’t be able to read these back in.

  • when reading - read exactly 17 Unicode codepoints

%"S

use double-quotes to delimit string

%'S

use single-quotes to delimit string

%cS

use any character (c) to delimit string

%{(S)}

quoted string, starting with (, ending with ), where the parens could be replaced by arbitrary characters

%*S

quoted string, the arg before the string to specifies quote character

%/a+/

where any regular expression can be used instead of a+ consume one or more ‘a’s when reading, gives an error when printing, and does not assign to any arguments (note - regular expression support is dependent on RE2 build; see Regex)

%/(a+)/

consume one or more ‘a’s and then set the corresponding string argument to the read value

%17/a+/

match a regular expression up to 17 bytes (note that %.17/a+/, which would mean to match 17 characters, is not supported).

%/*/

next argument contains the regular expression to match

General Conversion

%?

Use the fileWriter/fileReader’s associated serializer/deserializer to write or read a value.

For example, read and write a record in JSON format:

use IO, JSON;

record R {
  // fields...
}

var f = open("data.json", ioMode.cwr),
    r: R;

// write an 'R' in JSON format
f.writer(serializer = new jsonSerializer()).writef("%?", new R(/* ... */));

// read into an 'R' from JSON format
f.reader(deserializer = new jsonDeserializer()).readf("%?", r);

Note About Whitespace

When reading, \n in a format string matches any zero or more space characters other than newline and then exactly one newline character. In contrast, " " matches at least one space character of any kind.

When writing, whitespace is printed from the format string just like any other literal would be.

Finally, space characters after a revcom will be ignored, so that a binary format string can appear more readable.

Format String Syntax in Detail

Chapel’s format strings are simpler than those in C in one way: it is no longer necessary to specify the types of the arguments in the format string. For example, in C the l in %ld is specifying the type of the argument for integer (decimal) conversion. That is not necessary in Chapel since the compiler is able to use type information from the call.

Format strings in Chapel consist of:

  • conversion specifiers e.g. "%xi" (described below)

  • newline e.g. "\n"

    • when writing - prints a newline

    • when reading - reads any amount of non-newline whitespace and then exactly one newline. Causes the format string not to match if it did not read a newline.

  • other whitespace e.g. " "

    • when writing - prints as the specified whitespace

    • when reading - matches at least one character of whitespace, possibly including newlines.

  • other text e.g. “test”

    • when writing - prints the specified text

    • when reading - matches the specified text

# Specifiers

All # specifiers must be enclosed in %{} syntax, for example %{#} is the shortest one, and %{#.#} is a more typical one. The integer portion of the number will be padded out to match the number of # s before the decimal point, and the number of # s after the decimal point indicate how many digits to print after the decimal point. In other words, display how many digits to use when printing a floating-point number by using the # symbol to stand for digits. The fractional portion of the number will be rounded appropriately and extra space will be made if the integer portion is too small:

writef("n:%{###.###}\n", 1.2349);
     // outputs:
     // n:  1.235

This syntax also works for numbers without a decimal point by rounding them appropriately.

A # specifier may start with a ..

writef("%{.##}\n", 0.777);
     // outputs:
     //  0.78

% Specifiers

Specifiers starting with % offer quite a few options. First, some basic rules.

%%

means a literal %

\n

means a literal newline

\\

means a single backslash

%{}

curly braces can wrap a % or # conversion specifier. That way, even odd specifiers can be interpreted unambiguously. Some of the more complex features require the use of the %{} syntax, but it’s always acceptable to use curly braces to make the format string clearer. Curly braces are required for # conversion specifiers.

In general, a % specifier consists of either text or binary conversions:

[optional flags]
[optional field width or size in bytes]
[optional . then precision]
[optional base flag]
[optional exponential type]
[conversion type]

Going through each section for text conversions:

[optional flags]
@

means “alternate form”. It means to print out a base when not using decimal (e.g. 0xFFF or 0b101011); and it will format a complex number with parens instead of as e.g. 1.0+2.0i

+

means to show a plus sign when printing positive numbers

0

means to pad numeric conversions with 0 instead of space

" "

(a space) leaves a blank before a positive number (in order to help line up with negative numbers)

<

left-justify the converted value instead of right-justifying. Note, if both 0 and < are given, the effect is as if only < were given.

^

center-justify the converted value instead of right-justifying. Note, if both 0 and ^ are given, zero-padding will only be applied to the left of the numerical value

>

explicitly denote right-justification

[optional field width]

When printing numeric or string values, the field width specifies the number of columns that the conversion should use to display the value. It can be *, which means to read the field width from an integral argument before the converted value.

For string conversions in readf (%s %" %' %//), the field width specifies the maximum number of bytes to read.

For numeric conversions in readf, the field width is ignored.

[optional . then precision]

When printing floating point values, the precision is used to control the number of decimal digits to print. For %r conversions, it specifies the number of significant digits to print; for %dr or %er conversions, it specifies the number of digits following the decimal point. It can also be *, which means to read the precision from an integral argument before the converted value.

For textual string conversions in writef, (%s %" %'), the precision indicates the maximum number of columns to print - and the result will be truncated if it does not fit. In readf for these textual string conversions, the precision indicates the maximum number of characters (e.g. Unicode codepoints) to input.

Providing a precision argument to an integral specifier (%i, %u, etc) will emit a warning. Using %n to specify precision for an integer is preferred.

The precision is silently ignored for for %// conversions.

[optional base flag]
d

means decimal (and not exponential for floating-point)

x

means lower-case hexadecimal

X

means upper-case hexadecimal

o

means octal

b

means binary

j

means JSON-style strings, numbers, and structures

h

means Chapel-style strings, numbers, and structures

'

means single-quoted string (with \ and ')

"

means double-quoted string (with \ and ")

[optional exponential type]
e

means floating-point conversion printing exponential -12.34e+56

E

means floating-point conversion printing uppercase exponential -12.34E+56

[conversion type]
n

means type-based number, allowing width and precision (size is not mandatory)

i

means integral conversion. Note that the size is mandatory for binary integral conversions

u

means unsigned integral conversion. Note that the size is mandatory for binary integral conversions

r

means real conversion (e.g. 12.23). Note that the size is mandatory for binary real conversions

m

means imaginary conversion with an i after it (e.g. 12.23i)

z

means complex conversion. Note that the size is mandatory for binary complex conversions

s

means string conversion

S

means a quoted string conversion

{cS}

means string conversion with quote char c

{*S}

means string conversion with quote char in argument before the string

{xSy}

means string conversion with left and right quote chars x and y

/.../

means a regular expression (for reading only)

{/.../xyz}

means regular expression with flags xyz

c

means a Unicode character - either the first character in a string or an integral character code

Formatted I/O Examples

writef("%5i %5s %5r\n", 1, "test", 6.34);
     // outputs:
     //    1  test  6.34

writef("%2.4z\n", 43.291 + 279.112i);
     // outputs:
     // 43.29 + 279.1i

writef('%"S\n', "test \"\" \'\' !");
     // outputs:
     // "test \"\" '' !"
writef("%'S\n", "test \"\" \'\' !");
     // outputs:
     // 'test "" \'\' !'
writef("%{(S)}\n", "test ()", "(", ")");
     // outputs:
     // (test (\))


writef("|%40s|\n", "test");
writef("|%<40s|\n", "test");
writef("|%^40s|\n", "test");
writef("|%>40s|\n", "test")
     // outputs:
     // |                                    test|
     // |test                                    |
     // |                  test                  |
     // |                                    test|

writef("123456\n");
writef("%6.6'S\n", "a");
writef("%6.6'S\n", "abcdefg");
writef("%.3'S\n", "a");
writef("%.3'S\n", "abcd");
     // outputs:
     // 123456
     //    'a'
     // 'a'...
     // 'a'
     // ''...


var s:string;
var got = readf(" %c", s);
// if the input is " a", "\na", "  a", etc, s will contain "a"
// if the input is "b", got will be false and s will contain ""

var s:string;
var got = readf("\n%c", s);
// if the input is "\na", or " \na", s will contain "a"
// if the input is "b", got will be false and s will be ""

var got = readf("%/a+/");
// if the input is "a" or "aa" (and so on), got will return true
// if the input is "c" got will be false

var s:string;
var got = readf("%/a(b+)/", s);
// if the input is "c" got will be false and s will be ""
// if the input is "ab", got will be true and s will be "b"
// if the input is "abb", got will be true and s will be "bb"

FormattedIO Functions and Types

proc fileWriter.writef(fmtStr: ?t, const args ...?k) throws  where isStringType(t) || isBytesType(t)

Write arguments according to a format. See Formatted I/O.

Arguments:
  • fmt – the format as string or bytes

  • args – 0 or more arguments to write

Throws:
  • IllegalArgumentError – if an unsupported argument type is encountered.

  • SystemError – if the arguments could not be written.

proc fileReader.readf(fmtStr: ?t, ref args ...?k) : bool throws  where isStringType(t) || isBytesType(t)

Read arguments according to a format. See Formatted I/O.

Note

Intents for all arguments except the format string are ref. If readf is used with formats that require an additional argument such as %*i and %*S, then those arguments cannot be constants. Instead, store the value into a variable and pass that.

Arguments:
  • fmt – the format as string or bytes

  • args – the arguments to read

Returns:

true if all arguments were read according to the format string, false on EOF.

Throws:
  • UnexpectedEofError – If EOF was encountered before data could be read.

  • SystemError – If the arguments could not be read.

proc readf(fmt: string, ref args ...?k) : bool throws

Call stdin.readf; see fileReader.readf.

proc string.format(args ...?k) : string throws

Return a new string consisting of values formatted according to a format string. See Formatted I/O.

Arguments:
  • this – the format string

  • args – the arguments to format

Returns:

the resulting string

Throws:
  • UnexpectedEofError – The size of the temporary buffer was exceeded while writing the string.

  • BadFormatError – Improperly formatted values.

  • SystemError – If the string could not be formatted for another reason.

proc bytes.format(args ...?k) : bytes throws

Return a new bytes consisting of values formatted according to a format bytes. See Formatted I/O.

Arguments:
  • this – the format bytes

  • args – the arguments to format

Returns:

the resulting bytes

Throws:
  • UnexpectedEofError – The size of the temporary buffer was exceeded while writing the bytes.

  • BadFormatError – Improperly formatted values.

  • SystemError – If the bytes could not be formatted for another reason.

proc fileReader.extractMatch(m: regexMatch, ref arg) throws

Sets arg to the string of a match.

Assumes that the fileReader has been marked before where the captures are being returned. Will change the fileReader offset to just after the match. Will not do anything if error is set.

Arguments:
  • m – a Regex.regexMatch storing a location that matched

  • arg – an argument to retrieve the match into. If it is not a string, the string match will be cast to arg.type.

Throws:

SystemError – If a match could not be extracted.

proc ref fileReader.search(re: regex(?), ref captures ...?k) : regexMatch throws

Search for an offset in the fileReader from the current offset matching the passed regular expression, possibly pulling out capture groups. If there is a match, leaves the fileReader offset at the beginning of the match. If there is no match, the fileReader offset will be advanced to the end of the fileReader (or end of the file).

Throws a SystemError if an error occurs.

Arguments:
  • re – a Regex.regex record representing a compiled regular expression.

  • captures – an optional variable number of arguments in which to store the regions of the file matching the capture groups in the regular expression.

Returns:

the region of the fileReader that matched

iter fileReader.matches(re: regex(?), param captures = 0, maxmatches: int = max(int))

Enumerates matches in the string as well as capture groups.

Yields tuples of Regex.regexMatch objects, the 1st is always the match for the whole pattern.

At the time each match is returned, the fileReader offset is at the start of that match. Note though that you would have to use IO.fileReader.advance to get to the offset of a capture group.

After yielding each match, advances to just after that match and looks for another match. Thus, it will not return overlapping matches.

In the end, leaves the fileReader offset at the end of the last reported match (if we ran out of maxmatches) or at the end of the fileReader (if we no longer matched).

Holds the fileReader lock for the duration of the search.

Arguments:
  • re – a Regex.regex record representing a compiled regular expression.

  • captures – an optional compile-time constant representing the number of captures to be yielded in tuple elements.

  • maxmatches – the maximum number of matches to report.

Yields:

tuples of Regex.regexMatch objects, where the first element is the whole pattern. The tuples will have 1+captures elements.