# String Operations

Course: [Python](https://www.devtutorials.ai/learn/python) · Section: Reference Types
Source: https://www.devtutorials.ai/learn/python/reference-types/string-operations

> Creating and slicing strings, escape sequences, three ways to format, and the string methods grouped by job: case, search, validation, split and join.

Almost everything a program handles is text.

A name typed into a box. A line read from a file. A message shown on screen. A date before it becomes a date. Even numbers arrive as text — you met that with `input()` in the very first lesson.

## What You Will Learn

In this lesson, you will learn:

- Every way to write a string, and why Python has so many
- How to reach one character, or a whole run of them
- How to join, repeat, compare and search text
- The characters you cannot type directly, and how to write them
- Three ways to put values inside a sentence
- The string methods worth knowing, grouped by the job they do

By the end of this lesson, you will be able to write strings every way Python allows, reach and change text through indexing and slicing, put values inside sentences with f-strings, and use the string methods to search, clean and reshape text.

Because strings appear everywhere in Python programs, the skills from this lesson will be used repeatedly in later topics.

## Introduction to Strings

### What Is a String?

Python's name for text is `str`, short for **string**, because it is a string of characters joined together. A **string** is a sequence of characters, and each character has a position, starting at 0.

Here is text doing a few of the things it knows how to do:

```python runnable title="Text, and a few things it can do"
student = "Asha"

print(student.upper())
print(len(student))
print(student[0])
print(student + " scored 78")
```

The text knows how to make itself uppercase, count its own characters, hand over any one of them, and join itself to another piece.

A string is a run of characters in order, and every one of them has a position.

You can walk through those positions one at a time, exactly as you did with arrays:

```python runnable title="A string is a sequence"
student = "Asha"

print(student[0])
print(student[3])
print(len(student))

for letter in student:
    print(letter)
```

Anything you learned about indexing an array applies here unchanged.

### Creating Strings

You create a string by putting characters inside quote marks.

```python runnable title="Three ways to write the same thing"
a = "Asha"
b = 'Asha'
c = str("Asha")

print(a, b, c)
print(a == b == c)
```

`str()` also turns other values into text:

```python runnable title="Making text out of other values"
print(str(78))
print(str(78.5))
print(str(True))
print(str([78, 85]))
```

### Single and Double Quotes

Single and double quotes do exactly the same thing. Python has both so you can put one kind inside the other.

```python runnable title="Quotes inside quotes"
remark = "Asha's work is good"
title = 'She said "well done" today'

print(remark)
print(title)
```

Using the wrong one stops the program:

```python runnable expect-error title="A quote that ends the string early"
remark = 'Asha's work is good'
print(remark)
```

The string ended at the second `'`, and what followed made no sense. Use double quotes around text containing an apostrophe.

Pick one style and keep to it. Double quotes are the more common default.

### Triple Quotes

Three quote marks let a string run over several lines.

```python runnable title="A string that spans lines"
report = """Report card
Student: Asha
Marks: 78"""

print(report)
print(len(report))
```

The line breaks you typed are part of the string.

Triple quotes are also what docstrings use, which you met in the functions lesson.

### Multiline Strings

There are two other ways to build text over several lines.

```python runnable title="Three ways to get the same two lines"
a = """Line one
Line two"""

b = "Line one\nLine two"

c = ("Line one\n"
     "Line two")

print(a == b == c)
print(a)
```

`\n` is a line break written as two characters. The third form joins neighbouring strings automatically, which is handy for a long line of text with no breaks in it:

```python runnable title="Splitting a long line in the source only"
message = (
    "This message is long enough to be awkward on one line, "
    "so it is written in pieces that Python joins back together."
)

print(message)
print("Line breaks in it:", message.count("\n"))
```

The text has no line break at all — only the source code is split.

A backslash at the end of a line inside triple quotes stops the first line break:

```python runnable title="Stopping the first line break"
report = """\
Report card
Student: Asha"""

print(report)
```

### String Type (type())

Knowing the type matters because strings behave differently from numbers. Two values may look similar on the screen but act completely differently in code.

You can check what type a value is, which is how you confirm what you are holding is text:

```python runnable title="Checking the type"
student = "Asha"
marks = 78

print(type(student))
print(type(marks))
print(isinstance(student, str))
print(type(str(marks)))
```

Remember that `"78"` and `78` are different types, and `"78" + 5` fails while `"78" + "5"` gives `"785"`.

### String Immutability

**A string cannot be changed after it is made.** This is called being **immutable**.

```python runnable expect-error title="Trying to change one character"
student = "Asha"

student[0] = "M"
```

`TypeError: 'str' object does not support item assignment`.

Every method that looks like it changes a string actually returns a **new** string:

```python runnable title="The original never changes"
student = "Asha"

upper = student.upper()

print("Original:", student)
print("New one:", upper)
```

So to change a string, you reassign the name:

```python runnable title="Reassigning the name"
student = "Asha"
student = student.upper()

print(student)
```

Immutability sounds like a limit and is mostly a protection: text handed to a function cannot be altered behind your back.

`student.upper()` on its own line does nothing useful. A string method returns a new string, so you have to store or use what comes back.

## String Operations

### String Indexing

Reaching a single character works exactly as it does in an array — counting from the front, or from the back:

```python runnable title="Positions from the front and the back"
student = "Asha"

print(student[0])
print(student[-1])
print(student[1], student[-3])
```

And going past the end raises, again exactly as it does in an array:

```python runnable expect-error title="Past the end"
student = "Asha"
print(student[4])
```

### String Slicing

A **slice** takes a run of characters.

```text
text[start:stop:step]
```

It starts at `start` and stops **before** `stop`, exactly like `range()`.

```python runnable title="Taking a run of characters"
report = "Asha scored 78 in Maths"

print(report[0:4])
print(report[:4])
print(report[5:11])
print(report[-5:])
print(report[::2])
print(report[::-1])
```

Each part can be left out: no start means from the beginning, no stop means to the end, and a step of `-1` reverses.

A slice never raises `IndexError`, even when the numbers are out of range:

```python runnable title="A slice that is too big is simply trimmed"
student = "Asha"

print(repr(student[0:100]))
print(repr(student[10:20]))
```

An out-of-range slice gives an empty string, while an out-of-range index raises. That difference catches people out.

### String Concatenation (+)

`+` joins two pieces of text into one:

```python runnable title="Joining text"
student = "Asha"
subject = "Maths"

print(student + " - " + subject)
```

`+` only joins text to text:

```python runnable expect-error title="Joining text to a number"
student = "Asha"
marks = 78

print(student + " scored " + marks)
```

`TypeError: can only concatenate str (not "int") to str`. Convert with `str(marks)`, or use an f-string, which does it for you.

Joining many strings with `+` in a loop is slow, because each `+` builds a whole new string. `join()` is the right tool, and it appears later in this lesson.

### String Repetition (*)

`*` repeats a string a number of times:

```python runnable title="Repeating text"
print("-" * 30)
print("ab" * 3)
print("Report card".center(30, "="))
```

A separator line made with `*` is clearer than thirty typed dashes, and easy to change.

### String Comparison

Strings compare character by character, using each character's number in the character set.

```python runnable title="Comparing text"
print("Asha" == "Asha")
print("Asha" == "asha")
print("Asha" < "Ravi")
print("apple" < "banana")
```

Capital letters come before small ones, which surprises everyone at first:

```python runnable title="Why 'Z' is less than 'a'"
print("Z" < "a")
print(ord("Z"), ord("a"))
print(sorted(["banana", "Apple", "cherry"]))
```

To compare fairly, lower both sides:

```python runnable title="Comparing without the capitals getting in the way"
first = "ASHA"
second = "asha"

print(first == second)
print(first.lower() == second.lower())
print(sorted(["banana", "Apple", "cherry"], key=str.lower))
```

### Membership Operators (in, not in)

`in` answers whether one piece of text sits inside another:

```python runnable title="Is it inside?"
remark = "Good work this term"

print("work" in remark)
print("Work" in remark)
print("exam" not in remark)
print("work" in remark.lower())
```

`in` is the simplest way to search text, and the one to reach for when you only need a yes or no.

### Special Characters

Some characters cannot be typed directly into a string: a quote that would end it, a tab, a line break.

### Escape Sequences

A backslash followed by a letter is an **escape sequence** — two characters you type that mean one character in the string.

<div className="tscroll">

| You type | You get |
|---|---|
| `\n` | a new line |
| `\t` | a tab |
| `\\` | one backslash |
| `\"` | a double quote |
| `\'` | a single quote |
| `\u00e9` | a character by its number, here `é` |

</div>

```python runnable title="Escape sequences in action"
print("Line one\nLine two")
print("Name\tMarks")
print("Asha\t78")
print("A backslash: \\")
print("She said \"well done\"")
print("Caf\u00e9")
```

They are two characters in the source and one in the string:

```python runnable title="Counting what is really there"
text = "a\tb"

print(len(text))
print(repr(text))
```

`repr()` shows a string the way you would type it, which is the quickest way to see what is actually in it.

A path is where escapes bite:

```python runnable title="A backslash that was not meant as an escape"
print(len("C:\temp"))
print(repr("C:\temp"))
print(repr(r"C:\temp"))
```

`\t` in `C:\temp` became a tab. An `r` before the quote makes a **raw string**, where a backslash is just a backslash. Use raw strings for Windows paths and for regular expressions.

### String Formatting

Putting values inside a sentence. Python has three ways, and they arrived in this order.

#### % Formatting

The oldest form, borrowed from C. You will meet it in old code.

```python runnable title="Percent formatting"
student = "Asha"
marks = 78
average = 78.456

print("%s scored %d" % (student, marks))
print("Average: %.1f" % average)
print("%s: %d (%.1f%%)" % (student, marks, average))
```

`%s` is text, `%d` a whole number, `%.1f` a decimal to one place, and `%%` a literal percent sign. Readable enough for one value, awkward for several, and it is easy to get the order wrong.

#### format()

The second form to arrive was a method on the string itself:

```python runnable title="The format method"
student = "Asha"
marks = 78

print("{} scored {}".format(student, marks))
print("{0} scored {1}, and {0} passed".format(student, marks))
print("{name} scored {score}".format(name=student, score=marks))
print("{:>10}|{:<10}|{:^10}|".format("right", "left", "centre"))
print("{:,.2f}".format(1234.5))
```

Numbers and names let you reuse a value or put things in any order. The part after `:` is a **format spec**, controlling width, alignment and decimal places.

#### f-Strings

The modern way, and the one to use. Put `f` before the quote and write the value inside curly brackets, where it belongs in the sentence.

```python runnable title="f-strings"
student = "Asha"
marks = 78
average = 78.456

print(f"{student} scored {marks}")
print(f"{student} needs {100 - marks} more")
print(f"Average: {average:.1f}")
print(f"{student:>10}|{marks:<5}|")
print(f"{1234.5:,.2f}")
```

You can do a small calculation inside the brackets, and the same format specs work.

`=` inside the brackets prints the expression and its value, which is excellent for checking what a program is doing:

```python runnable title="The debugging form"
marks = 78
average = 78.456

print(f"{marks=}")
print(f"{average=:.1f}")
print(f"{marks * 2=}")
```

Here are the three forms together:

<div className="tscroll">

| Form | Looks like | Use it |
|---|---|---|
| `%` | `"%s scored %d" % (a, b)` | only when reading old code |
| `format()` | `"{} scored {}".format(a, b)` | when the template is built separately |
| f-string | `f"{a} scored {b}"` | everywhere else |

</div>

Use f-strings. The values sit where they appear in the sentence, so there is no counting of placeholders and no chance of putting them in the wrong order.

So far you have used strings with operators such as + and *. Strings also come with many built-in methods that help you search, clean and transform text.

## String Methods

Every string carries its methods with it. There are around forty; these are the ones worth knowing, grouped by what they do.

Remember throughout: **every one of these returns a new string. None of them changes the original.**

### Case Conversion Methods

#### capitalize()

First character upper, everything else lower.

```python runnable title="capitalize"
print("asha SHARMA".capitalize())
```

#### casefold()

Like `lower()`, but more aggressive, for comparing text across languages.

```python runnable title="casefold against lower"
german = "STRASSE"
sharp_s = "ß"

print(german.lower())
print(sharp_s.lower())
print(sharp_s.casefold())
```

`ß` lowercases to itself but casefolds to `ss`, so casefolding makes the two German spellings match. Use `casefold()` for comparing, `lower()` for displaying.

#### lower() and upper()

These are the two you will use most, usually to make comparisons fair:

```python runnable title="lower and upper"
student = "Asha Sharma"

print(student.lower())
print(student.upper())
print(student.lower() == "ASHA SHARMA".lower())
```

#### swapcase()

```python runnable title="swapcase"
print("Asha Sharma".swapcase())
```

#### title()

Capitalises the first letter of every word.

```python runnable title="title, and where it goes wrong"
print("asha sharma".title())
print("asha's report".title())
```

`Asha'S` is wrong — `title()` treats the apostrophe as the end of a word. For names, `capitalize()` on each word is safer.

### Search and Count Methods

#### find() and rfind()

`find()` gives the position of the first match, or `-1` when there is none.

```python runnable title="find and rfind"
report = "maths 78, science 85, maths 60"

print(report.find("maths"))
print(report.rfind("maths"))
print(report.find("history"))
```

`rfind()` searches from the right. Neither one ever raises.

#### index() and rindex()

The same two searches, but they raise instead of returning `-1`.

```python runnable expect-error title="index raises when it fails"
report = "maths 78"

print(report.index("maths"))
print(report.index("history"))
```

Use `find()` when a miss is expected and normal; use `index()` when a miss means something is wrong.

#### count()

`count()` answers how many times one piece of text appears in another:

```python runnable title="count"
report = "maths 78, science 85, maths 60"

print(report.count("maths"))
print(report.count("m"))
print("Mississippi".count("ss"))
```

Counting does not overlap: `"aaa".count("aa")` is 1, not 2.

#### startswith() and endswith()

These answer whether a string begins or ends with a given piece:

```python runnable title="startswith and endswith"
filename = "report_card.py"

print(filename.startswith("report"))
print(filename.endswith(".py"))
print(filename.endswith((".py", ".txt")))
```

A tuple checks several endings at once, which is neater than three `or`s.

### Validation Methods

These all answer `True` or `False` about what a string contains. They are how you check input before converting it.

```python runnable title="The whole validation family at once"
samples = ["Asha", "78", "78.5", "Asha78", "   ", "Asha Sharma", ""]

print(f"{'text':<12}{'alnum':<8}{'alpha':<8}{'digit':<8}{'space':<8}{'title':<8}")
for text in samples:
    print(f"{repr(text):<12}{text.isalnum()!s:<8}{text.isalpha()!s:<8}{text.isdigit()!s:<8}{text.isspace()!s:<8}{text.istitle()!s:<8}")
```

An empty string is `False` for all of them, which is usually what you want.

#### isalnum(), isalpha(), isascii()

```python runnable title="Letters, digits and plain ASCII"
print("Asha78".isalnum())
print("Asha 78".isalnum())
print("Asha".isalpha())
print("Asha".isascii())
print("café".isascii())
```

A space is neither a letter nor a digit, so `isalnum()` is `False` for anything with one in it.

#### isdecimal(), isdigit(), isnumeric()

Three methods that look identical and are not. They differ on unusual characters.

```python runnable title="Where the three differ"
for text in ["123", "²", "½", "12.3"]:
    print(f"{text!r:>8}  isdecimal={text.isdecimal()!s:<6} isdigit={text.isdigit()!s:<6} isnumeric={text.isnumeric()}")
```

`²` counts as a digit but not a decimal. `½` is numeric but neither of the others. And `"12.3"` fails all three, because the dot is not a digit.

**Use `isdecimal()`** when you are about to call `int()`. It is the strictest of the three and the one that matches what `int()` accepts.

```python runnable title="Checking before converting"
for text in ["78", "78.5", "seventy"]:
    if text.isdecimal():
        print(text, "->", int(text))
    else:
        print(text, "-> not a whole number")
```

#### islower(), isupper(), isspace(), istitle()

```python runnable title="Case and whitespace checks"
print("asha".islower())
print("ASHA".isupper())
print("   ".isspace())
print("Asha Sharma".istitle())
print("Asha sharma".istitle())
```

#### isidentifier() and isprintable()

```python runnable title="Valid names, and characters you can see"
print("student_name".isidentifier())
print("2nd_student".isidentifier())
print("class".isidentifier())
print("Asha".isprintable())
print("Asha\tSharma".isprintable())
```

`isidentifier()` checks the naming rules from lesson 2 — but note it says `True` for `class`, because keywords follow the same spelling rules. Use `keyword.iskeyword()` as well if that matters.

### Modification Methods

#### replace()

`replace()` swaps every copy of one piece of text for another:

```python runnable title="replace"
report = "maths 78, maths 60"

print(report.replace("maths", "Mathematics"))
print(report.replace("maths", "Mathematics", 1))
print(report)
```

The third number limits how many are replaced. The original is untouched, as always.

#### strip(), lstrip(), rstrip()

Remove characters from the ends. With no argument, they remove whitespace — which is what user input is full of.

```python runnable title="Cleaning up the ends"
typed = "   Asha   "

print(repr(typed.strip()))
print(repr(typed.lstrip()))
print(repr(typed.rstrip()))
```

Given characters, they strip any of those characters from the ends:

```python runnable title="Stripping particular characters"
print("***Asha***".strip("*"))
print("www.school.com".strip("wcom."))
```

The second one is a trap: `strip()` removes **any** of those characters, in any order, not the whole word. That is `removeprefix()`'s job.

#### removeprefix() and removesuffix()

```python runnable title="Removing exactly one piece"
print("report_card.py".removesuffix(".py"))
print("Mr Ravi".removeprefix("Mr "))
print("Asha".removesuffix(".py"))
print("www.school.com".removeprefix("www."))
```

These remove the whole piece, once, and leave the string alone when it does not match. They are what most people mean when they wrongly reach for `strip()`.

### Split and Join Methods

#### split() and rsplit()

`split()` breaks a string into a list.

```python runnable title="Breaking text apart"
line = "Asha,78,Maths"

print(line.split(","))
print("Asha Sharma scored well".split())
print(line.split(",", 1))
print("a,b,c".rsplit(",", 1))
```

With no argument, `split()` breaks on any whitespace and ignores runs of it, which is what you want for a sentence. `rsplit()` counts its splits from the right.

#### splitlines()

`splitlines()` breaks text into lines:

```python runnable title="Breaking into lines"
report = """Report card
Student: Asha
Marks: 78"""

for line in report.splitlines():
    print(repr(line))
```

Better than `split("\n")`, because it handles the line endings used by other systems too.

#### join()

`join()` is `split()` backwards: it glues a list of strings together with a separator.

```python runnable title="join"
subjects = ["Maths", "Science", "English"]

print(", ".join(subjects))
print(" - ".join(subjects))
print("".join(subjects))
```

The separator is the string you call it on, which reads backwards at first and quickly becomes natural.

Every item must already be text:

```python runnable expect-error title="join needs text"
marks = [78, 85, 60]

print(", ".join(marks))
```

```python runnable title="Converting first"
marks = [78, 85, 60]

print(", ".join(str(mark) for mark in marks))
```

`join()` is also the right way to build a long string, because it works out the total size once instead of rebuilding on every `+`.

#### partition() and rpartition()

`partition()` splits at the **first** match and gives back three pieces: before, the separator, and after.

```python runnable title="partition"
line = "maths:78:A"

print(line.partition(":"))
print(line.rpartition(":"))
print("Asha".partition(":"))
```

You always get three pieces, even when the separator is missing, so nothing has to be checked before unpacking:

```python runnable title="Three pieces, always"
subject, found, rest = "maths:78".partition(":")

print(repr(subject), repr(found), repr(rest))
```

### Alignment and Padding Methods

These make columns line up in printed output.

```python runnable title="The four padding methods"
print("Asha".center(20, "-"))
print("Asha".ljust(20, ".") + "|")
print("Asha".rjust(20, ".") + "|")
print("7".zfill(3))
print("-7".zfill(5))
```

`zfill()` pads with zeros and keeps a minus sign at the front, which is why it is not just `rjust(n, "0")`.

```python runnable title="A table built with padding"
rows = [("Maths", 78), ("Science", 85), ("English", 60)]

print("Subject".ljust(12) + "Marks".rjust(6))
print("-" * 18)
for subject, marks in rows:
    print(subject.ljust(12) + str(marks).rjust(6))
```

#### expandtabs()

Turns tabs into spaces, using a tab stop you choose.

```python runnable title="expandtabs"
line = "Asha\t78"

print(repr(line))
print(repr(line.expandtabs(4)))
print(line.expandtabs(4))
```

An f-string with widths is usually clearer than relying on tabs.

### Translation and Encoding Methods

#### encode()

Turns text into **bytes**, which is what files and networks actually carry.

```python runnable title="encode"
text = "café"

data = text.encode("utf-8")

print(data)
print(len(text), "characters ->", len(data), "bytes")
print(data.decode("utf-8"))
```

`é` takes two bytes in UTF-8, so four characters became five bytes. UTF-8 is the encoding to use unless something forces otherwise.

#### maketrans() and translate()

`maketrans()` builds a table of character swaps, and `translate()` applies it in one pass.

```python runnable title="maketrans and translate"
table = str.maketrans("aeiou", "12345")

print("Asha scored".translate(table))

remove_vowels = str.maketrans("", "", "aeiou")
print("Asha scored".translate(remove_vowels))
```

A third argument lists characters to delete. For a handful of single-character swaps this is faster and clearer than several `replace()` calls.

### Built-in Functions with Strings

#### len()

`len()` counts the characters in a string:

```python runnable title="len"
student = "Asha Sharma"

print(len(student))
print(len(student.replace(" ", "")))
print(len(""))
```

`len()` counts characters, including spaces.

#### max() and min()

On a string, these compare character by character:

```python runnable title="max and min on characters"
print(max("Asha"))
print(min("Asha"))
```

On a list of strings they compare whole words:

```python runnable title="max and min on words"
subjects = ["Maths", "Science", "English"]

print(max(subjects))
print(min(subjects))
print(max(subjects, key=len))
```

`key=len` changes the question from "which comes last alphabetically" to "which is longest".

Before moving on, here are some of the mistakes beginners make most often when working with strings.

## Common mistakes

Each row is one mistake. The middle column is what you will actually see on screen.

<div className="tscroll">

| Mistake | What you see | Why it happens | Fix |
|---|---|---|---|
| Expecting a method to change the string | The text never changes | Strings are immutable; methods return a new one | `student = student.upper()` |
| Assigning to one character | `TypeError: 'str' object does not support item assignment` | A string cannot be changed in place | Build a new string, or use `replace()` |
| Joining text to a number with `+` | `TypeError: can only concatenate str` | `+` needs both sides to be text | `str(marks)`, or an f-string |
| An apostrophe inside single quotes | `SyntaxError` | The second quote ends the string | Use double quotes around it |
| `\t` inside a Windows path | A tab appears in the middle of the path | `\t` is an escape sequence | Use a raw string: `r"C:\temp"` |
| Comparing text without lowering it | `"Asha" == "asha"` is `False` | Capital and small letters are different characters | Compare `.lower()` on both sides |
| `strip("www.")` to remove a prefix | More characters vanish than expected | `strip()` removes **any** of those characters | `removeprefix("www.")` |
| `index()` when the text may be missing | `ValueError: substring not found` | `index()` raises; `find()` returns `-1` | Use `find()`, or check with `in` |
| `join()` on a list of numbers | `TypeError: sequence item 0: expected str` | Every item must already be text | `", ".join(str(m) for m in marks)` |
| `isdigit()` before `int()` | `ValueError` on strings like `"²"` | `isdigit()` accepts characters `int()` rejects | Use `isdecimal()` |
| Building a long string with `+` in a loop | It works, but slowly | Each `+` builds a whole new string | Collect the pieces and `join()` them |
| `title()` on a name with an apostrophe | `Asha'S Report` | `title()` treats `'` as a word break | Capitalise each word yourself |

</div>

## What to Remember

- **A string is a run of characters in order**, and every one has a position starting at 0.
- Single and double quotes are the same; triple quotes span lines.
- **Strings are immutable.** Every method returns a new string, so you must store what comes back.
- A slice `text[start:stop]` stops before `stop`, and an out-of-range slice gives `""` rather than an error.
- `+` joins text to text only; `*` repeats it.
- Comparison is character by character, and capital letters come before small ones.
- A backslash starts an escape sequence; an `r` before the quote turns that off.
- **Use f-strings.** `%` and `format()` are for reading older code.
- `find()` returns `-1` on a miss; `index()` raises.
- `strip()` removes **any** of the given characters; `removeprefix()` removes one whole piece.
- `split()` breaks text into a list and `join()` puts one back together — and `join()` needs every item to be text.
- **`isdecimal()` is the check to use before `int()`**, not `isdigit()`.
- `ljust()`, `rjust()`, `center()` and `zfill()` line columns up; `encode()` turns text into bytes.

Next: **Date and Time**
