Part 14: Text
Text has been in every program since Hello, World, and so far it has been simple: a literal in quotes, printed with {}. This part looks underneath. A literal turns out to be a slice of UTF-8 bytes, which is why its length can surprise you; the Text package adds views that promise their bytes are text, Strings that own their bytes, and builders that grow them. Then the part turns outwards — Unicode's three ways of counting characters, laying out columns of numbers, rendering text you keep, parsing numbers back out of it, and reading lines a person types.
What you will learn
- What a string literal is — a read-only
char8[..]of UTF-8 bytes — and the escapes it can hold. - The three encodings,
c8,c16andc32, and why lengths count code units rather than characters. - Borrowing text with
StringView, owning it withString, and building it withStringBuilder. - Checking and decoding UTF-8, and telling bytes, scalars and graphemes apart.
- Changing case correctly beyond ASCII, where one letter can become two.
- Placeholder specs for width, alignment, precision, bases, zeros and signs.
- Rendering into a
StringwithRender, parsing numbers withParseInt32, and reading lines withReadLine.
The text types at a glance
flowchart LR
lit(["A literal<br/>char8[..]"]) -- "StringView::FromValidated<br/>or FromBytes (checked)" --> view["StringView<br/>borrowed, known to be UTF-8<br/>(14.3)"]
lit -- "String::FromBytes" --> str["String<br/>owns its bytes<br/>(14.4)"]
sb["StringBuilder<br/>grows a buffer<br/>(14.5)"] -- "IntoString" --> str
sb -- "View" --> view
str -- "View" --> view
r["Render(pattern, values)<br/>(14.11)"] --> str
in["ReadLine<br/>(14.13)"] -- "appends to" --> sb
view -- "ParseInt32<br/>(14.12)" --> num(["a number"])| You have… | And want to… | Use |
|---|---|---|
| bytes that might not be text | be sure they are UTF-8 | StringView::FromBytes or Validate |
| text someone else owns | trim, search, split it | StringView |
| text a function made | hand it back, keep it | String |
| pieces arriving one at a time | join them without copying them all | StringBuilder |
| values and a pattern | text you keep | Render |
| text that should be a number | the number, or why not | ParseInt32 and friends |
Lessons
| Lesson | What you will learn | |
|---|---|---|
| 14.1 | String literal | what a string literal is: read-only char8 code units |
| 14.2 | Encoding | c8, c16 and c32 literals, and code units versus characters |
| 14.3 | String view | borrow text without copying it |
| 14.4 | String | own text that lives as long as you need it |
| 14.5 | String builder | build text a piece at a time |
| 14.6 | UTF-8 | check and decode UTF-8 bytes |
| 14.7 | Unicode | bytes, code points and grapheme clusters, and why their counts differ |
| 14.8 | Unicode case | change case beyond ASCII, where one letter can become two |
| 14.9 | Format | control width and alignment when formatting values |
| 14.10 | Format number | control precision and number base when formatting numbers |
| 14.11 | Render | format values into a String instead of the console |
| 14.12 | Parse | turn text into a number, and handle text that is not one |
| 14.13 | Input | read a line typed by the user, and notice when input ends |
Before you start
Finish Part 13: Generics. Text leans on almost everything before it: slices from Part 5, optionals and fallibles from Part 8 and Part 9 — nearly every text operation can fail — Destructor from Part 11 for the memory a String gives back, and Display and Iterator from Part 12. Each lesson's package is in the Examples repository's Text/ folder:
cd Examples/Text/StringLiteral
rux run
Several lessons pass an Allocator around without explaining it yet. For now it is simply where a String's bytes come from; Part 15: Memory opens it up.
After this part
Part 15: Memory explains the allocators and pointers this part used without looking inside — the @written of Unicode case and the Allocator every String was given. Part 16: Numbers then ends with the checkpoint projects Circle and Quadratic, which read numbers typed by the user with this part's ReadLine and the Format package's parsers.
For the language rules behind literals, see String literals, Literals and the character types in the Rux Reference, and the Text, Format and Io packages in the API reference.
13.6 Generic sum
Build a sum from type parameters — T | U — see it collapse when T and U are the same type, and end its match in else.
14.1 String literal
See that a string literal is a read-only char8[..] slice: its length counts bytes, escapes write awkward characters, and changing text means copying it first.