Skip to content

Cookbook ​

Short answers to "how do I ...?". Each recipe is a complete program with its real output; the reference has the details.

f90
program print_a_string
!< Three ways to print a string.
use stringifor
implicit none
type(string) :: s

s = 'Hello World'
print '(A)', s//''          ! concatenation gives a character
print '(A)', s%chars()      ! the raw characters
print '(DT)', s             ! defined I/O
endprogram print_a_string
$ print_string
Hello World
Hello World
Hello World

//'' is the idiom used in all these pages: it works wherever a character is expected.

Assign, concatenate, compare ​

f90
program operators
!< Assignment, concatenation and comparison.
use stringifor
implicit none
type(string)              :: a, b, c
character(:), allocatable :: chars

a = 'Hello'                  ! from a character
b = a                        ! from a string
c = a//' '//'World'          ! // gives a character, assigned to a string
chars = a//' again'          ! or kept as a character
c = a .cat. ' World'         ! .cat. gives a string
print '(A)', c//''
print '(A)', chars
print '(3(L1,1X))', a == b, a == 'Hello', a /= c
print '(3(L1,1X))', a < c, 'Apple' < a, a >= b
endprogram operators
$ operators
Hello World
Hello again
T T T
T T T

// gives a character, .cat. a string; the comparisons accept a character on either side.

Change the case ​

f90
program case_conversion
!< Upper, lower and the like.
use stringifor
implicit none
type(string) :: s

s = 'Hello World'
print '(A)', s%upper()//''
print '(A)', s%lower()//''
print '(A)', s%swapcase()//''
print '(A)', s%capitalize()//''
print '(2(L1,1X))', s%is_upper(), s%is_lower()
endprogram case_conversion
$ letter_case
HELLO WORLD
hello world
hELLO wORLD
Hello world
F F

camelCase, snake_case, Start Case ​

f90
program word_case
!< Word-level case styles.
use stringifor
implicit none
type(string) :: s

s = 'the quick brown fox'
print '(A)', s%startcase()//''
print '(A)', s%camelcase()//''
print '(A)', s%snakecase()//''
s = 'the-quick-brown-fox'
print '(A)', s%camelcase(sep='-')//''
endprogram word_case
$ wordcase
The Quick Brown Fox
TheQuickBrownFox
the_quick_brown_fox
TheQuickBrownFox

The words are separated by blanks, or by sep.

Remove blanks, or other characters, around a string ​

f90
program strip_blanks
!< Remove what surrounds a string.
use stringifor
implicit none
type(string) :: s

s = '   hello world   '
print '(A)', '['//s%strip()//']'              ! both ends
print '(A)', '['//s%trim()//']'               ! the end only
print '(A)', '['//s%adjustl()//']'            ! moved to the left, same length
s = '--=hello world=--'
print '(A)', '['//s%strip(remove='-=')//']'   ! any character of a set
print '(A)', '['//s%lstrip(remove='-=')//']'  ! the beginning only
print '(A)', '['//s%rstrip(remove='-=')//']'  ! the end only
s = achar(9)//' hello world'//new_line('a')
print '(A)', '['//s%strip(whitespace=.true.)//']'  ! tabs and new lines too
endprogram strip_blanks
$ strip
[hello world]
[   hello world]
[hello world      ]
[hello world]
[hello world=--]
[--=hello world]
[hello world]

strip removes the blanks at both ends, or the characters of the set remove; lstrip and rstrip one end only. whitespace=.true. removes tabs, new lines and the other whitespace too, as Python str.strip().

Replace, collapse, insert ​

f90
program replace_text
!< Replace, collapse, insert.
use stringifor
implicit none
type(string) :: s

s = 'a-b-c-d'
print '(A)', s%replace(old='-', new=' + ')//''
print '(A)', s%replace(old='-', new='', count=2)//''   ! the first two only
s = 'too    many     blanks'
print '(A)', s%unique(' ')//''
s = 'Helo'
print '(A)', s%insert(substring='l', pos=3)//''
endprogram replace_text
$ replace
a + b + c + d
abc-d
too many blanks
Hello

Tidy whitespace, repeats, tabs and quotes ​

f90
program tidy
!< Whitespace, repeated characters, tabs, character sets and quotes.
use stringifor
implicit none
type(string) :: s

s = '  too   many'//achar(9)//'blanks  '
print '(A)', '['//s%compact()//']'
print '(A)', '['//s%compact(sep='_')//']'
s = 'Mississippi --- yes!!!'
print '(A)', s%squeeze()//''
print '(A)', s%squeeze(set='-!')//''
s = 'id'//achar(9)//'name'//achar(9)//'value'
print '(A)', s%expand_tabs(8)//''
s = 'hello world'
print '(A)', s%transliterate('lo', 'LO')//''
print '(A)', s%transliterate('aeiou', '')//''
s = 'say "hi"'
s = s%quote()
print '(A)', s//''
print '(A)', s%unquote()//''
endprogram tidy
$ tidy
[too many blanks]
[too_many_blanks]
Misisipi - yes!
Mississippi - yes!
id      name    value
heLLO wOrLd
hll wrld
"say ""hi"""
say "hi"

compact collapses whitespace, squeeze repeated characters, expand_tabs aligns on tab stops, transliterate maps a set of characters onto another; quote and unquote add and remove quotes, doubling the inner ones.

Tell letters, digits, punctuation and blanks apart ​

f90
program char_classes
!< The class of the characters of some strings.
use stringifor
implicit none
type(string) :: words(5)
integer      :: w

words(1) = 'Fortran'
words(2) = 'F2023'
words(3) = 'c0ffee'
words(4) = '?!,'
words(5) = ' '
print '(A)', 'word      alpha alnum xdigit punct space'
do w = 1, size(words)
  print '(A,5L6)', words(w)%ljust(10)//'', words(w)%is_alpha(), words(w)%is_alnum(), words(w)%is_xdigit(), &
                   words(w)%is_punct(), words(w)%is_space()
enddo
endprogram char_classes
$ char_classes
word      alpha alnum xdigit punct space
Fortran        T     T     F     F     F
F2023          F     T     T     F     F
c0ffee         F     T     T     F     F
?!,            F     F     F     T     F
               F     F     F     F     T

Each test is true if all the characters of the string are in the class, false for a null string.

Split a line into words ​

f90
program split_words
!< Split a string into tokens.
use stringifor
implicit none
type(string)              :: s
type(string), allocatable :: tokens(:)
integer                   :: t

s = 'the quick  brown   fox'
call s%split(tokens=tokens)                         ! on blanks, repeated ones count as one
print '(I0,A)', size(tokens), ' words, the last one is "'//tokens(size(tokens))//'"'

s = '2001-07-14'
call s%split(tokens=tokens, sep='-')
print '(*(A,:,"/"))', (tokens(t)//'', t=size(tokens), 1, -1)

s = 'key = value = with = equals'
call s%split(tokens=tokens, sep=' = ', max_tokens=1)  ! split once
print '(A)', '['//tokens(1)//'] ['//tokens(2)//']'
endprogram split_words
$ split_words
4 words, the last one is "fox"
14/07/2001
[key] [value = with = equals]

Repeated separators count as one, and the ones at the ends are ignored. max_tokens is the number of splits. To keep the empty fields, as in a CSV record, pass keep_empty=.true..

Join an array of strings ​

f90
program join_strings
!< Join an array into one string.
use stringifor
implicit none
type(string) :: glue, words(3), joined
character(5) :: chars(3)

words(1) = 'one' ; words(2) = 'two' ; words(3) = 'three'
glue = ', '
joined = glue%join(array=words)                 ! the string is the separator
print '(A)', joined//''
print '(A)', glue%join(array=words, sep='-')//'' ! or pass one

chars = ['alpha', 'beta ', 'gamma']
joined = strjoin(array=chars, sep='+')          ! no separator string needed; characters are trimmed
print '(A)', joined//''
endprogram join_strings
$ join_strings
one, two, three
one-two-three
alpha+beta+gamma

join is a method, its string is the default separator; strjoin is a function of the module.

Parse comma-separated values ​

f90
program csv_line
!< Parse a line of comma-separated values, empty cells included.
use stringifor
implicit none
type(string)              :: line
type(string), allocatable :: cells(:)
real(R8P)                 :: value, total
integer                   :: c, iostat, bad

line = ' 12.5 , 7 ,  n/a,, 30.25 '
call line%split(tokens=cells, sep=',', keep_empty=.true.)  ! the empty cell keeps its column
cells = cells%strip()                                      ! every cell at once
total = 0._R8P
bad = 0
do c = 1, size(cells)
  call cells(c)%read_number(value, iostat=iostat)
  if (iostat == 0) then
    total = total + value
  else
    bad = bad + 1
  endif
enddo
print '(I0,A,F0.2,A,I0,A)', size(cells), ' cells, the numbers sum to ', total, ', ', bad, ' are not numbers'
endprogram csv_line
$ csvline
5 cells, the numbers sum to 49.75, 2 are not numbers

keep_empty=.true. keeps the empty cell in its column, and read_number reports, with a positive iostat, a cell that is not a number instead of returning 0 or NaN.

Split once, at the first separator ​

f90
program partition_once
!< Split at the first separator, keeping the three parts.
use stringifor
implicit none
type(string) :: s, parts(3)

s = 'name = John = Smith'
parts = s%partition(sep=' = ')
print '(A)', '['//parts(1)//'] ['//parts(2)//'] ['//parts(3)//']'
endprogram partition_once
$ partition
[name] [ = ] [John = Smith]

Take a part of a string ​

f90
program slice_a_string
!< Substrings, with a stride too.
use stringifor
implicit none
type(string) :: s

s = 'Hello World'
print '(A)', s%slice(first=1, last=5)
print '(A)', s%slice(first=7)                   ! to the end
print '(A)', s%slice(last=5)                    ! from the beginning
print '(A)', s%slice(stride=2)                  ! every other character
print '(A)', s%slice(stride=-1)                 ! backwards
print '(A)', '['//s%slice(first=20, last=30)//']' ! out of the string: clamped, never out of bounds
endprogram slice_a_string
$ slice
Hello
World
Hello
HloWrd
dlroW olleH
[]

slice returns a character; its three arguments are all optional.

Reverse the characters, or the words ​

f90
program reverse_things
!< Reverse the characters or the words.
use stringifor
implicit none
type(string) :: s

s = 'the sky is blue'
print '(A)', s%reverse()//''
print '(A)', s%reverse_words()//''
s = 'usr/local/lib'
print '(A)', s%reverse_words(sep='/')//''
endprogram reverse_things
$ reverse
eulb si yks eht
blue is sky the
lib/local/usr

Pad to a width ​

f90
program pad_a_string
!< Pad to a width.
use stringifor
implicit none
type(string) :: s

s = '42'
print '(A)', s%fill(width=6)//''                             ! zeros on the left
print '(A)', s%fill(width=6, right=.true.)//''
print '(A)', s%fill(width=6, filling_char='.')//''
s = 'name'
print '(A)', '['//s%fill(width=10, right=.true., filling_char=' ')//']'
endprogram pad_a_string
$ pad
000042
420000
....42
[name      ]

Center or justify in a width ​

f90
program align
!< Strings centered or justified in a given width.
use stringifor
implicit none
type(string) :: s

s = 'title'
print '(A)', '['//s%center(11)//']'
print '(A)', '['//s%center(11, '=')//']'
print '(A)', '['//s%ljust(11, '.')//']'
print '(A)', '['//s%rjust(11)//']'
print '(A)', '['//s%center(3)//']'
endprogram align
$ align
[   title   ]
[===title===]
[title......]
[      title]
[title]

center, ljust and rjust work as the Python methods: a string already as wide as the width is unchanged.

Find something in a string ​

f90
program search_text
!< Look for something in a string.
use stringifor
implicit none
type(string) :: s

s = 'report_2001_final.tar.gz'
print '(2(L1,1X))', s%start_with('report'), s%end_with('.gz')
print '(I0)', s%count('_')
print '(I0)', s%index('2001')
print '(I0)', s%index('.', back=.true.)
print '(I0)', s%scan('0123456789')              ! the first digit
print '(I0)', s%verify('abcdefghijklmnopqrstuvwxyz')  ! the first character that is not a letter
s = 'aaaa'
print '(I0,1X,I0)', s%count('aa'), s%count('aa', overlapping=.true.)
s = 'a.b.c.d'
print '(I0,1X,I0)', s%index('.', occurrence=2), s%index('.', back=.true., occurrence=2)
endprogram search_text
$ search
T T
2
8
22
8
7
2 3
4 4

count and index look for occurrences that do not overlap, as Python: 'aaaa' holds 2 'aa', 3 with overlapping=.true.. index(substring, occurrence=k) is the k-th occurrence, counted from the end with back=.true., 0 if there are fewer.

Get the text between two tags ​

f90
program tagged_text
!< The text between two tags.
use stringifor
implicit none
type(string) :: s, found
integer      :: first, last

s = '<b>bold</b> plain <b>bold again</b>'
found = s%search(tag_start='<b>', tag_end='</b>', istart=first, iend=last)
print '(A,2(1X,I0))', found//'', first, last
endprogram tagged_text
$ tags
<b>bold</b> 1 11

search returns the first tagged text, tags included, and optionally where it starts and ends.

Check whether a string is a number ​

f90
program number_check
!< Is it a number?
use stringifor
implicit none
type(string) :: s(6)
integer      :: i

s(1) = '42' ; s(2) = '-3.14' ; s(3) = '6.02e23' ; s(4) = '1.' ; s(5) = '12 apples' ; s(6) = '007'
print '(A)', 'string      number integer real digit'
do i = 1, size(s)
  print '(A,4(L1,6X))', s(i)%fill(width=12, right=.true., filling_char=' ')//'', &
        s(i)%is_number(), s(i)%is_integer(), s(i)%is_real(), s(i)%is_digit()
enddo
endprogram number_check
$ number_check
string      number integer real digit
42          T      T      F      T
-3.14       T      F      T      F
6.02e23     T      F      T      F
1.          T      F      T      F
12 apples   F      F      F      F
007         T      T      F      T

is_digit is true when every character is a digit; a real has a decimal point or an exponent, so an integer is not a real.

Convert a string to a number ​

f90
program number_cast
!< From a string to a number.
use stringifor
implicit none
type(string) :: s
real(R8P)    :: x
integer(I4P) :: n

s = '3.4e2'
if (s%is_number()) x = s%to_number(kind=1._R8P)   ! the kind of the argument selects the result
print '(F0.1)', x
s = '42'
if (s%is_integer()) n = s%to_number(kind=1_I4P)
print '(I0)', n + 1
x = s%to_number(kind=1._R8P)                      ! an integer string is a valid real
print '(F0.1)', x
endprogram number_cast
$ number_cast
340.0
43
42.0

Check first: on a string that is not a number to_number gives 0 (integer kinds) or NaN (real kinds).

Convert a string to a number, with an error status ​

f90
program checked_cast
!< Numbers read from strings, with an error status.
use stringifor
implicit none
type(string)      :: fields(3)
real(R8P)         :: value
integer           :: iostat
character(len=99) :: iomsg
integer           :: f

fields(1) = '3.25'
fields(2) = 'n/a'
fields(3) = '1e3'
do f = 1, size(fields)
  call fields(f)%read_number(value, iostat=iostat, iomsg=iomsg)
  if (iostat == 0) then
    print '(A,F8.2)', fields(f)//' -> ', value
  else
    print '(A)', fields(f)//' -> error: '//trim(iomsg)
  endif
enddo
endprogram checked_cast
$ checked_cast
3.25 ->     3.25
n/a -> error: the string is not a number
1e3 ->  1000.00

read_number reports the failure as a read statement: iostat is positive and iomsg says why.

Convert a number to a string ​

f90
program number_to_string
!< From a number to a string.
use stringifor
implicit none
type(string) :: s

s = 42
print '(A)', s//''
s = -127_I1P
print '(A)', s//''
s = 2.5_R4P
print '(A)', s//''
s = 1._R8P/3._R8P
print '(A)', s//''
s = 255
print '(A)', s%hex()//' '//s%hex(uppercase=.true.)
s = -1
print '(A)', s%hex(bits=16)//''                   ! two's complement on 16 bits
endprogram number_to_string
$ number_string
+42
-127
+0.250000000E+01
+0.33333333333333331E+000
ff FF
ffff

A real is written with all the significant digits of its kind. hex reads the integer in the string.

Read a whole file ​

f90
program read_a_file
!< Read a whole file.
use stringifor
implicit none
type(string), allocatable :: lines(:)
type(string)              :: content

call read_file(file='notes.txt', lines=lines)     ! one string for each line
print '(I0,A)', size(lines), ' lines, the last is "'//lines(size(lines))//'"'

call content%read_file(file='notes.txt')          ! the whole file in one string
print '(I0,A,I0,A)', content%len(), ' characters, ', content%count(new_line('a')), ' line ends'
endprogram read_a_file
$ readfile
3 lines, the last is "third line"
34 characters, 3 line ends

The first form is a subroutine of the module, the second a method reading the file as one string, line ends included.

Read a file line by line ​

f90
program read_line_by_line
!< Read a file one line at a time.
use stringifor
implicit none
type(string) :: line
integer      :: unit, iostat, n

n = 0
open(newunit=unit, file='poem.txt', status='old', action='read')
do
  call line%read_line(unit=unit, iostat=iostat)
  if (iostat /= 0) exit                           ! the end of the file, or an error
  n = n + 1
  print '(I0,A)', n, ': ['//line//']'
enddo
close(unit)
endprogram read_line_by_line
$ readline
1: [roses are red]
2: []
3: [violets are blue]

iostat is zero for every line read, empty ones included, and not zero at the end of the file.

Write a file ​

f90
program write_a_file
!< Write strings to a file.
use stringifor
implicit none
type(string) :: lines(3)

lines(1) = 'bread'
lines(2) = 'milk'
lines(3) = 'coffee'
call write_file(file='shopping.txt', lines=lines)
print '(A)', 'written'
endprogram write_a_file
$ writefile
written
$ cat shopping.txt
bread
milk
coffee

Write and read lines through an open unit ​

f90
program unit_io
!< Lines written to and read from a unit already open.
use stringifor
implicit none
type(string)              :: line, text
type(string), allocatable :: lines(:)
integer                   :: unit, l

open(newunit=unit, file='notes.txt', status='replace')
line = 'first line'
call line%write_line(unit=unit)                       ! one string, one line
text = 'second line'//new_line('a')//'third line'
call text%write_lines(unit=unit)                      ! one string, a line for each line it holds
call read_lines(unit=unit, lines=lines)               ! rewinds the unit, one string for each line
close(unit, status='delete')
do l = 1, size(lines)
  print '(I0,A)', l, ': '//lines(l)
enddo
endprogram unit_io
$ unit_io
1: first line
2: second line
3: third line

write_line writes a string as one line, write_lines writes each line it holds as a line. read_lines rewinds the unit and reads every line: as a method into one string, as the procedure of the module into an array.

Save strings in a binary file ​

f90
program binary_io
!< Strings saved to and loaded from an unformatted file.
use stringifor
implicit none
type(string) :: saved(3), loaded(3)
integer      :: unit, s

saved(1) = 'Venture'
saved(2) = '  blanks kept  '
saved(3) = ''
open(newunit=unit, file='names.bin', form='unformatted', access='stream', status='replace')
write(unit) saved                                     ! each string: its length, then its characters
close(unit)
open(newunit=unit, file='names.bin', form='unformatted', access='stream', status='old')
read(unit) loaded
close(unit, status='delete')
do s = 1, size(loaded)
  print '(I2,A)', loaded(s)%len(), ' characters: ['//loaded(s)//']'
enddo
endprogram binary_io
$ binary_io
 7 characters: [Venture]
15 characters: [  blanks kept  ]
 0 characters: []

An unformatted write stores each string as its length followed by its characters, and read gets it back exactly, blanks and empty strings included. The format is the same as that of string_type in the Fortran stdlib.

Read strings from the standard input ​

f90
program read_standard_input
!< Read strings with list-directed input.
use stringifor
implicit none
type(string) :: first, second

read *, first, second
print '(A)', '['//first//'] ['//second//']'
endprogram read_standard_input
$ echo '"two words" three' | read_stdin
[two words] [three]

A list-directed read takes one blank-delimited word, or a quoted text, for each string.

Take a path apart ​

f90
program path_pieces
!< The pieces of a file name.
use stringifor
implicit none
type(string) :: path

path = '/home/user/data/archive.tar.gz'
print '(A)', path%basedir()//''
print '(A)', path%basename()//''
print '(A)', path%extension()//''
print '(A)', path%basename(strip_last_extension=.true.)//''
print '(A)', path%basename(extension='.tar.gz')//''
endprogram path_pieces
$ paths
/home/user/data
archive.tar.gz
.gz
archive.tar
archive

List the files matching a pattern ​

f90
program list_files
!< The files matching a pattern.
use stringifor
implicit none
type(string)              :: s
type(string), allocatable :: files(:)
integer                   :: f

call s%glob(pattern='data/*.csv', list=files)
do f = 1, size(files)
  print '(A)', files(f)//''
enddo
endprogram list_files
$ glob
data/cars.csv

glob runs the ls command: it works on Unix-like systems only. Only the wildcards *, ? and [...] are special: any other character of the pattern is part of the names searched.

Filter names with a wildcard pattern ​

f90
program wildcards
!< The names matching a wildcard pattern.
use stringifor
implicit none
type(string) :: names(5)
integer      :: n

names(1) = 'report-2025.csv'
names(2) = 'report-2026.csv'
names(3) = 'report-2026.txt'
names(4) = 'notes.txt'
names(5) = 'Report-2026.csv'
do n = 1, size(names)
  if (names(n)%match('report-202[5-9].csv')) print '(A)', names(n)//''
enddo
print '(5L2)', names%match('*.txt')
endprogram wildcards
$ wildcards
report-2025.csv
report-2026.csv
 F F T T F

match needs no file system: it works on any system, on names already in memory, and it is elemental.

Get a name for a temporary file ​

f90
program temporary_name
!< A name for a temporary file.
use stringifor
implicit none
type(string) :: s, name

name = s%tempname(prefix='scratch-')              ! a name not used by any file of the directory
print '(L1,1X,L1)', name%start_with('scratch-'), name%len() > len('scratch-')
endprogram temporary_name
$ tempname
T T

The name is not used by any file of the directory; it changes at each call, so the example prints what does not.

Wrap a paragraph in justified lines ​

f90
program justify_text
!< Wrap a paragraph in justified lines.
use stringifor
implicit none
type(string)              :: text
type(string), allocatable :: lines(:)
integer                   :: l

text = 'Fortran is a general-purpose, compiled imperative programming language '// &
       'that is especially suited to numeric computation and scientific computing.'
call text%justify(lines=lines, width=36)
do l = 1, size(lines)
  print '(A)', '|'//lines(l)//'|'
enddo
print '(A,I0)', 'the last word has length ', text%len_last_word()
endprogram justify_text
$ justify
|Fortran    is   a   general-purpose,|
|compiled    imperative   programming|
|language  that  is especially suited|
|to     numeric    computation    and|
|scientific computing.               |
the last word has length 10

The last line is left-justified and padded; a word longer than the width stays alone on its line.

Find what several strings start with ​

f90
program common_prefix
!< What several strings start with.
use stringifor
implicit none
type(string) :: files(3), prefix

files(1) = 'src/lib/stringifor.F90'
files(2) = 'src/lib/stringifor_string_t.F90'
files(3) = 'src/tests/stringifor/test.f90'
prefix = files(1)%common_prefix(files(2))         ! of two strings
print '(A)', prefix//''
prefix = files(1)%common_prefix(array=files)      ! of an array
print '(A)', prefix//''
endprogram common_prefix
$ prefix
src/lib/stringifor
src/

Compare two version numbers ​

f90
program compare_versions
!< Which version is newer?
use stringifor
implicit none
type(string) :: version

version = '1.10.0'
print '(I0)', version%compare_version('1.9.3')    !  1: newer
print '(I0)', version%compare_version('1.10')     !  0: the same, missing fields are zero
print '(I0)', version%compare_version('2.0')      ! -1: older
version = '2024-03'
print '(I0)', version%compare_version('2024-11', sep='-')
endprogram compare_versions
$ version
1
0
-1
-1

Fields of digits are compared as integers of any size, the others as text. It is not semantic versioning: 1.0.0-rc1 is greater than 1.0.0.

Encode and decode in base64 ​

f90
program base64
!< Encode and decode in base64.
use stringifor
implicit none
type(string) :: s, code

s = 'Hello World'
code = s%encode(codec='base64')
print '(A)', code//''
print '(A)', code%decode(codec='base64')//''
endprogram base64
$ encode_base64
SGVsbG8gV29ybGQ=
Hello World

Escape a character ​

f90
program escape_characters
!< Escape a character, and back.
use stringifor
implicit none
type(string) :: s, escaped

s = 'C:\temp\new'
escaped = s%escape(to_escape='\')
print '(A)', escaped//''
print '(A)', escaped%unescape(to_unescape='\')//''
endprogram escape_characters
$ escape
C:\\temp\\new
C:\temp\new
f90
program colours
!< Colours and styles for the terminal.
use stringifor
implicit none
type(string) :: s

s = 'error: the file is missing'
print '(A)', s%colorize(color_fg='red', style='bold_on')
s = 'warning: the file is empty'
print '(A)', s%colorize(color_fg='yellow')
s = 'done'
print '(A)', s%colorize(color_fg='green', style='underline_on')
endprogram colours

three coloured lines in a terminal

A method on every element of an array ​

f90
program arrays_of_strings
!< A method applied to every element of an array.
use stringifor
implicit none
type(string) :: names(3), glue
integer      :: n

names(1) = 'ada' ; names(2) = 'grace hopper' ; names(3) = 'linus'   ! elements of different lengths
names = names%startcase()                         ! the methods are elemental
print '(A)', glue%join(array=names, sep=', ')//''
print '(3(I0,1X))', names%len()
print '(3(L1,1X))', names%start_with('G')
n = maxloc(names%len(), dim=1)
print '(A)', 'the longest is '//names(n)
endprogram arrays_of_strings
$ arrays
Ada, Grace Hopper, Linus
3 12 5
F T F
the longest is Grace Hopper

The elements of an array of strings have each its own length.

Use the Fortran intrinsics on a string ​

f90
program intrinsics_on_strings
!< The Fortran intrinsics, on strings.
use stringifor
implicit none
type(string) :: s

s = '  hello  '
print '(A)', '['//trim(s)//']'
print '(A)', '['//adjustl(s)//']'
print '(I0)', len_trim(s)
print '(I0)', index(s, 'll')
print '(A)', repeat(s%strip(), 3)//''
endprogram intrinsics_on_strings
$ intrinsics
[  hello]
[hello    ]
7
5
hellohellohello

adjustl, adjustr, count, index, len_trim, repeat, scan, trim and verify accept a string. trim removes the trailing blanks only.