Chapter 12 — Key Takeaways (Strings and Text)
A one-page reference for modern Fortran text handling: self-sizing strings, the character intrinsics, and internal files.
The two (and a half) kinds of string
| Declaration | Kind | Length is… | Use it for |
|---|---|---|---|
character(len=n) :: s |
fixed-length | constant; value blank-padded | a field of known width; a scratch buffer |
character(:), allocatable :: s |
deferred-length | set by assignment; re-sizes | the default — strings that fit their contents |
character(len=*), intent(in) :: s |
assumed-length dummy | taken from the caller | every string procedure argument |
Reach for character(:), allocatable. It is the allocatable idea (Ch. 5, Ch. 11) applied to
characters: owns its memory, freed automatically, s = value reallocates to fit, len(s) is always exact.
The character intrinsics (what each returns)
| Call | Returns | Note |
|---|---|---|
len(s) |
declared/allocated length | includes trailing blanks |
len_trim(s) |
length without trailing blanks | 0 if all blank |
trim(s) |
s minus trailing blanks |
trim(adjustl(s)) strips both ends |
adjustl(s) |
left-justified; leading blanks → tail | length preserved |
adjustr(s) |
right-justified; trailing blanks → front | length preserved |
index(s, sub[, back]) |
1-based position of sub, else 0 |
back=.true. → last occurrence |
scan(s, set[, back]) |
first char in set, else 0 |
find a delimiter / a digit |
verify(s, set[, back]) |
first char not in set, else 0 |
== 0 ⇒ all chars are in set |
Idioms worth memorizing
- Strip both ends:
trim(adjustl(s)) - Present?
index(s, sub) > 0· Absent?index(s, sub) == 0 - All digits?
verify(tok, '0123456789') == 0 - Start of content (skip leading blanks):
verify(s, ' ') - File extension:
index(name, '.', back=.true.)
Concatenation and substrings
whole = 'heat' // '_' // 'map' ! // joins; length is the sum
part = s(3:7) ! substring: 1-based, inclusive, length j-i+1
- Always
trima fixed-length variable before//or its trailing blanks splice in:trim(dir) // '/' // file, neverdir // '/' // file. - A substring
s(i:j)is a string like any other; ifi > jit is zero-length.
Internal files (number ↔ text)
write(str, fmt) values ! number -> text (like sprintf / f-string)
read (str, fmt) variables ! text -> number (like sscanf / int(),float())
- The "unit" is a character variable; no
open, no disk. Same edit descriptors as Chapter 7. write(fname, '(a,i6.6,a)') 'heat_', step, '.vtk'→heat_000123.vtk.read(line, *) a, b, csplits'3 14 159'on blanks →3, 14, 159.
Edit descriptors you use here
| Descriptor | Effect | Example |
|---|---|---|
i0 |
integer, minimum width (never overflows) | 255 → 255 |
iw.m |
width w, ≥ m digits, zero-padded |
i6.6 of 123 → 000123 |
fw.d |
real, width w, d decimals |
f8.3 of 3.14159 → 3.142 |
a |
character, exact | 'heat' → heat |
Common pitfalls
- Trailing-blank splice:
dir // '/x'with fixed-lengthdirburies blanks. →trim(dir). indexis not a boolean:if (index(s,sub))doesn't compile; write> 0/== 0.- Field overflow →
*:i4.4of12345prints****. Size the field, or usei0. - 1-based, 0-when-absent: porting Python
find(0-based, −1 absent) needs two corrections. - Off-by-one in tokenizers: offsets from
scan/verifyonline(pos:)are relative — addpos-1.
The tokenizer, in one breath
verify finds where a token starts (first non-delimiter); scan finds where it ends (next
delimiter). Skip-then-take in a loop; a run of delimiters is skipped in one verify, so extra spaces
never make empty tokens. scan/verify take a set, so ' ,' tokenizes comma-or-space data unchanged.
Modern vs legacy (the point of the chapter)
| FORTRAN 77 | Modern | |
|---|---|---|
| Only string kind | fixed-length | deferred-length available |
| True length | tracked by hand in an integer | carried by the string (len(s)) |
| Build a value | write into s(a:b), update n |
s = s // piece |
Modern Fortran is a modern language: deferred-length strings delete the manual length counter — an entire class of bookkeeping and bugs — that FORTRAN 77 forced on you.
Project piece added this chapter
frame_name(step) — a function returning a deferred-length filename heat_NNNNNN.vtk built with an
internal-file write write(buf, '(a,i6.6,a)') 'heat_', step, '.vtk'. The six zero-padded digits make
frames sort in time order; Chapter 26 calls it to name per-timestep VTK output. Ceiling: i6.6 holds
999,999 steps — widen to i8.8 beyond that.
Key terms
deferred-length character · fixed-length character · assumed-length (len=*) · internal
file · substring · concatenation (//) · trim/adjustl (the character-intrinsic family) ·
index/scan/verify · tokenizer.