Popup YouTube Video
Sheerpower Logo

String Formatting with F$() and Sprintf$()


Formatted Strings

When you want to display information on the screen or write it to a file, the easiest approach is usually the print statement.

name$ = 'Sally' age = 26 print 'Hello '; name$; '. You are '; age; ' years old'

Sometimes, however, you do not want to print the information immediately. You may need to build the complete text first so you can place it on a webpage, store it in a database, save it as a note, or pass it to another routine.

In that case, the formatted result needs to be placed into a string variable. Sheerpower provides two major formatting functions for doing this. The simplest is f$().

name$ = 'Sally' age = 26 mytext$ = f$('Hello [[name$]]. You are [[age]] years old') print mytext$

The result is:

Hello Sally. You are 26 years old

Inside an f$() format string, anything between [[]] is evaluated and inserted into the resulting string.

name$ = 'Sally' years = 22 print f$('Her name was [[name$]], she was [[years]] years old.') ! Her name was Sally, she was 22 years old. print f$('[[ucase$(name$)]] has [[len(name$)]] letters') ! SALLY has 5 letters print f$('Total: [[sprintf$("%.2m",]]') ! Total: 1,234.50

Anything that can be used as an expression can appear between the brackets. This includes variables, arithmetic expressions, function calls, string slices, and other expressions whose values can be displayed.

print f$('Next year she will be [[years]].') print f$('First three letters: [[left$(name$, 3)]]') print f$('Uppercase name: [[ucase$(name$)]]')

Brackets used inside an expression are balanced normally, so an expression such as [[name$[1:3]]] works as expected.

Arrays can also be inserted. They are formatted the same way that print would display them. For example, if scores contains 90, 85, 77:

print f$('Scores: [[scores]]') ! Scores: 90 85 77

When you need special formatting, such as a fixed number of decimal places or thousands separators, use sprintf$() inside the formatted segment.

amount = 1234.5 text$ = f$('Total: [[sprintf$("%.2m",]]') print text$ ! Total: 1,234.50

The expressions are evaluated when f$() runs. This means a format string stored in a variable can be reused, and each use will insert the current values of its expressions.


Special Formatting using SPRINTF$()

string$ = sprintf$(string_format$, arg1, arg2, .. )
The name stands for "String Print-Formatted". The function name was chosen to match the name of similar functions found in programming languages such as C, C++, Java, Javascript, PYTHON, etc.

sprintf$() is a managed, printf-inspired formatting function with Sheerpower-specific extensions for grouping, dates, pluralization, title capitalization, positional masks and English number words. Formatting errors raise exceptions rather than corrupting runtime memory. Applications must still use explicit monetary rounding where needed.

Given the formatting string and a list of optional arguments, returns the string result of the arguments applied to the format. The arguments can be of any data type.

Simple Formatting Examples
Each % within the formatting string marks where the content of the additional arguments are substituted into the string. Each % marks the beginning of a format and is followed by an optional letter and other specifications.

Simple Substitution
age = 33 print sprintf$('Age is %', age) Age is 33 name$ = 'Sally Sue' age = 22 note$ = sprintf$('% is %', name$, age) print 'Here is my note: '; note$ Here is my note: Sally Sue is 22

Real and integer Formatting
In Sheerpower, the r and i formats are used for numeric values, representing Real and Integer types, respectively. For compatibility with other implementations of sprintf, the f format can also be used for Real numbers, and the d format can also be used for Integer numbers.
print sprintf$('PI is about %r', pi) print sprintf$('PI is about %i', pi) PI is about 3.1415926535897932 PI is about 3
Using a .n after the %, we can specify the number (.n) of decimal digits. This also rounds the number. For example, we might want to show a REAL rounded to three decimal digits:
print sprintf$('PI is about %.3r', 3.14159265) PI is about 3.142

Singulars and Plurals
One Sheerpower specific format is %p, which produces a word in its plural form if needed. The last numeric value that precedes the %p format determines if the word is produced as a singular or plural.
ox_counter = 56 print sprintf$('I have % %p.', ox_counter, 'ox') I have 56 oxen. ox_counter = 1 print sprintf$('I have % %p.', ox_counter, 'ox') I have 1 ox. print sprintf$('%p', 'foot') feet

Dates and times
To format dates and times you use the %t formatter followed by date/time item names. Item names have a @ prefix. The sprintf$() argument is the time in seconds as calculated by the seconds() function. If the seconds given is zero, then the current date and time is used.

The date/time item names are:
  • @yyyy -- Four digit year -- 2022
  • @yy -- Two digit year -- 22
  • @month -- Month name -- January
  • @mon -- Short month name -- Jan
  • @mm2 -- Two digit month -- 09
  • @mm -- One or Two digit month -- 9 or 10
  • @dd2 -- Two digit day -- 09
  • @dd -- One or two digit day number -- 9 or 10
  • @h2 -- Two digit hour -- 09
  • @h -- One or two digit hour -- 9 or 10
  • @mt -- Military time -- 14
  • @m2 -- two digit minute -- 09
  • @m -- One or two digit minute -- 9 or 10
  • @s2 -- Two digit seconds -- 09
  • @s -- one or Two digit seconds -- 9 or 10
  • @ampm -- AM or PM indicator
  • @day -- Day of the week -- Monday
  • @tz -- The machine's UTC offset -- -07:00 (or Z when exactly at UTC)
  • @ts -- The complete RFC 3339 timestamp in one item -- 2026-08-21T17:33:14-07:00 (equivalent to @yyyy-@mm2-@dd2T@mt:@m2:@s2@tz)
  • @mil -- military datetime -- 15-Jun-2022 07:38:10
  • @short -- short length datetime -- Jun09 13:54
If no prefixed item is given, the default of @short is used. If no sprintf$() argument is given, the current datetime is used. The formatting of @short is highly optimized. Over 10 million per second can be formatted. This makes it ideal for inclusion into log files.

f$ = "%tThe party is @month (month# @mm) @dd, @yyyy @mt:@m2:@s2 - or @h2:@m2:@s2 @ampm on a @day" now_secs = seconds('') print sprintf$(f$, now_secs) The party is June (month# 6) 10, 2022 05:32:28 - or 05:32:28 AM on a Friday f$ = '%t@month @dd2-@mon-@yyyy' now_secs = seconds('20221225 0000') print sprintf$(f$, now_secs) December 25-Dec-2022 print sprintf$('%t@mil Processing starting') 15-Jun-2022 08:26:47 Processing starting print sprintf$('%t@short Processing starting') Jun09 15:11 Processing starting print sprintf$('%t Processing started') Jun09 15:11 Processing started

Create Proper English Titles
Titles often follow special capitalization rules. Important words are capitalized, while smaller connecting words such as a, an, the, of, and to may remain lowercase when they are not the first word. In addition, hundreds of commom special cases are supported.

The %T format specifier, using a capital T, formats text using title capitalization.

In the example below, is is capitalized because it is a verb. In title capitalization, verbs are treated as important words, even when they are short.

my_text$ = 'this is a book title' print sprintf$('%T', my_text$) // outputs: This Is a Book Title

Dealing With String Substitutions
Often strings need to be formatted in specific ways. The %z format is used for this purpose. It supports two methods -- each character in turn substitutions using the "@" and segment substitutions using "[]":
ssn$ = '123456789' print sprintf$('%z SSN: @@@-@@-@@@@', ssn$) print sprintf$('%z SSN: [1:3]-[4:5]-[6:9]', ssn$)
Segments are the most versatile of the two methods. For each segment, specify [aaa:zzz] where aaa is the starting location in the string and zzz is the ending location. Note that the first location is one and the last location is the length of the string. The word "end" stands for the end of the string.

Within the "[]" one can also include the additional formatting options of "uc" or "lc" for uppercasing or lowercasing the segment:
a$='abcdefGHI' print sprintf$('%z[uc:1:3]-[4:5]-[lc:6:end]', a$) ABC-de-fghi

Formatting Money and Large Numbers
Another Sheerpower specific format is %m, which inserts commas into numbers as needed. It is frequently used when formatting money or large numbers. The .2 in the example below says two decimal digits will be returned. The number will also be rounded as needed.
cash = 1234567.887 print sprintf$('About $ %.2m', cash) About $ 1,234,567.89

Writing Numbers in Words

Sheerpower supports the %w format for producing the written-in-words version of a numeric value.

This is especially useful for checks, invoices, receipts, legal documents, and other business output where an amount must appear both numerically and in words.

Problem:
Business software often needs to print monetary amounts in words, such as "One thousand two hundred thirty four and 56/100".

Solution:
Use the %w format in sprintf$() to convert a numeric value into its written form. English whole-number words are followed by a truncated two-digit hundredths fraction. The fractional portion is produced in check style as and nn/100.

Efficiency:
By making written-number formatting part of sprintf$(), Sheerpower eliminates repetitive conversion code and keeps business formatting fast, consistent, and easy to read.

For example:

a = 1234.56 print sprintf$('%r Written: %w', a, a)
Output: 1234.56 Written: One thousand two hundred thirty four and 56/100
Note: For financial output, the fractional portion is handled using truncation to two decimal digits, not rounding. This follows check-writing convention and ensures that the written value never exceeds the numeric value.
amount = 1234.567 print sprintf$('%r Written: %w', amount, amount)

Output: 1234.567 Written: One thousand two hundred thirty four and 56/100

This behavior is intentional. A rounded result such as 57/100 would overstate the written amount. For check and payment text, truncation is the safer and more conventional rule.


Some additional examples:

print sprintf$('%w', 0) Zero and 00/100 print sprintf$('%w', 0.75) Zero and 75/100 print sprintf$('%w', 1.01) One and 01/100 print sprintf$('%w', -42.10) Negative forty two and 10/100

Use %w when you want the number written in words. Use other numeric formats such as %r or %m when you want conventional numeric display.

Positioning with Horizontal Tabs
Sheerpower also supports a horizontal tab format using %h. The argument value is the tab position. Tab position one is the first position.
tab_pos = 15 age = 45 print sprintf$('The age was: %h%i',tab_pos, age) The age was: 45

Column Alignment
Column alignment is accomplished by specifying the fixed width of a given number or string. The width is specified by supplying a number directly after the %. For example, to give a fixed width of 10 characters:
print sprintf$('Number: %10i and more.', 123) Number: 123 and more.
By default, numbers are right-justified within columns. To left-justify a number, give a negative column width:
print sprintf$('Number: %-10i and more.', 123) Number: 123 and more.

Octal, Hexadecimal, and Binary
The %o, %x, and %b are used to format numbers into octal, hexadecimal, and binary.
print sprintf$('%i in Octal: %o Hex: %x Binary: %b', 123, 123, 123, 123) 123 in Octal: 173 Hex: 7b Binary: 1111011

Embedding Special Characters
Sometimes there is a need to embed special characters into the format. The "\" (back-slash) is used for this purpose. For example, to insert a "new line" character into the format use \n. For example:
print sprintf$('Hello\nWorld') Hello World

Below is the full list of special characters:
CombinationResult
\bBackspace
\fForm-feed
\nNew line
\rReturn
\tTab
\0nnnGenerate a character based
on the octal value
of nnn
For example \0102 >> B
\\The "\" character
print sprintf$('The letter (\0102)') The letter (B)


All Conversion Formats
Below is the full set of sprintf$() conversion formats. Formats marked SP are Sheerpower extensions (not part of C's printf).

Flags — a flag goes between the % and the format letter, and flags may be combined (for example %-8.2f):
FlagMeaningExample → Result
N (a number)Minimum field width, right-justifiedsprintf$('%5i', 42)   42
-Left-justify within the widthsprintf$('%-5i|', 42)42   |
0Pad a number with leading zerossprintf$('%05i', 42)00042
.NPrecision: number of decimal placessprintf$('%.2f', 3.14159)3.14
+Force a leading + on positive reals (%r/%f/%m; integer formats ignore it)sprintf$('%+.2f', 42)+42.00

The conversion letters:
FormatMeaningExample → Result
%General substitution (any type)sprintf$('%', 99)99
%sString (a width justifies it: %-6s left, %6s right)sprintf$('%s', 'hello')hello
%i %dIntegersprintf$('%i', 42)42
%r %fReal number (.N decimals; + forces a sign)sprintf$('%.2r', 3.14159)3.14
%eScientific notationsprintf$('%e', 3.14159)3.141590e00
%gReal, compactsprintf$('%g', 3.14159)3.14159
%m (SP)Number with comma grouping (.N decimals)sprintf$('%.2m', 1234.5)1,234.50
%o %x %bOctal, hexadecimal, binarysprintf$('%x', 123)7b
%cThe character with the given code (like C); given a string, its first charactersprintf$('%c', 66)B
%h (SP)Horizontal tab to a column (argument = the position)sprintf$('%h%i', 15, 45) → aligns 45 at column 15
%p (SP)Pluralize the following word by the countsprintf$('% %p', 2, 'item')2 items
%t (SP)Date/time with @-items (see the Date and Time page)sprintf$('%t@yyyy', secs)2026
%T (SP)Title Casesprintf$('%T', 'hello world')Hello World
%w (SP)Number written in words (check style)sprintf$('%w', 1234)One thousand two hundred thirty four and 00/100
%z (SP)Lay the string into a template: @ takes the next character, [a:b] copies a range (a template must have at least one @ or [a:b])sprintf$('%z@@@-@@-@@@@', '123456789')123-45-6789

Literal %, @, [ and ]
To print a literal percent sign, double it: %%. A single % begins a conversion, so an undoubled % with no matching argument raises an error — always write %%.
print sprintf$('50%% off, % left', 5) 50% off, 5 left
The characters @, [ and ] are ordinary literals everywhere except inside a %t template (where @ begins a date/time item) and a %z template (where @ is a placeholder and [ begins a range). Outside those two, type them directly:
print sprintf$('user@host has % msgs', 3) user@host has 3 msgs print sprintf$('arr[%] set', 7) arr[7] set
There is no escape for a literal @ or [ inside a %t or %z template, so build any such text outside the %t/%z part (a separate sprintf$(), or plain string concatenation).
How %z handles string length
With the @ mask, each @ takes the next character of the string in order:
  • If the string has more characters than the mask has @s, the extra trailing characters are dropped: sprintf$('%z@@@', 'hello')hel.
  • If the string has fewer characters than the mask has @s, it raises an error ("Not enough data for @ substitutions").
A [a:b] range copies characters by absolute position and clamps to the string's length, so a range past the end simply stops at the last character: sprintf$('%z[1:10]', 'hi')hi.
Using %p with more than one count
Each %p pluralizes its word using the most recent numeric % before it, so several count/word pairs work in one format string:
print sprintf$('% %p and % %p', 2, 'cat', 1, 'dog') 2 cats and 1 dog
If no number precedes a %p, it defaults to the plural form (sprintf$('%p', 'foot')feet) — so always give %p a count.
sprintf$() and Program Safety
Sheerpower's implementation of sprintf$() is completely safe. If a wrong data type is passed, Sheerpower will attempt to convert it to the correct data type. If this cannot be done, an exception is raised, explaining the problem. If too few or too many arguments are passed, an exception is raised. In no case will the Sheerpower runtime environment crash or become polluted when processing the sprintf$() function.

(Show/Hide Sheerpower SPRINTF and F$() Takeaways)
Hide Description

    

       


      

Enter or modify the code below, and then click on RUN

Looking for the full power of Sheerpower?
Check out the Sheerpower website. Free to download. Free to use.