Strings: A Deeper Look
What You Will Learn
- Format string content with f-strings and the
formatmethod. - Concatenate and repeat strings.
- Remove whitespace from the beginning and end of strings.
- Change character case.
- Compare strings.
- Search for and replace substrings.
- Split strings into tokens and join strings together.
- Use character-testing methods such as
isdigit()andisalpha(). - Use raw strings when backslashes should be treated literally.
- Create regular expressions for matching, validating, replacing and extracting text.
- Understand metacharacters, character classes, quantifiers, anchors and grouping.
- Use pandas with regular expressions for data cleaning and data munging.
Chapter Structure
8.1 Introduction
A string is a sequence of characters. You have already used strings for names, messages and input. Now we look at the operations that become especially useful when programs work with large amounts of text.
8.2 Formatting Strings
Formatting makes information easier to read. Python provides powerful formatting through f-strings and the older, still common str.format() method.
8.2.1 Presentation Types
A format specifier tells Python how a value should be displayed.
| Type | Meaning | Example |
|---|---|---|
d | Integer | f'{10:d}' |
b | Binary representation of an integer | f'{10:b}' |
o | Octal representation | f'{10:o}' |
x / X | Hexadecimal representation | f'{255:x}' |
c | Character represented by an integer code | f'{65:c}' |
s | String | f'{"hello":s}' |
f | Fixed-point floating-point format | f'{17.489:.2f}' |
e / E | Scientific notation | f'{1000:.2e}' |
print(f'{17.489:.2f}')
print(f'{10:d}')
print(f'{65:c} {97:c}')17.49
10
A a.2f is used with floating-point and Decimal values. Formatting is type-dependent.8.2.2 Field Widths and Alignment
A field width reserves a number of character positions for the formatted value. Numbers are right-aligned by default, while strings are left-aligned by default.
print(f'[{27:10d}]')
print(f'[{"hello":10}]')
print(f'[{27:<10d}]')
print(f'[{"hello":>10}]')
print(f'[{27:^10d}]')[ 27]
[hello ]
[27 ]
[ hello]
[ 27 ]| Specifier | Meaning |
|---|---|
< | Left-align |
> | Right-align |
^ | Center |
8.2.3 Numeric Formatting
You can display signs, fill unused positions with zeros and group large numbers with commas.
print(f'{27:+10d}')
print(f'{27:+010d}')
print(f'{12345678:,d}')
print(f'{123456.78:,.2f}') +27
+000000027
12,345,678
123,456.78: starts the format specification inside { }. For example, {value:,.2f} means comma grouping and two digits after the decimal point.8.2.4 String's format Method
The format() method was the traditional way to format strings before f-strings were introduced. You will still see it in older programs and documentation.
'{:.2f}'.format(17.489)
'{} {}'.format('Amanda', 'Cyan')
'{0} {0} {1}'.format('Happy', 'Birthday')
'{first} {last}'.format(first='Amanda', last='Gray')
'{last} {first}'.format(first='Amanda', last='Gray')'17.49'
'Amanda Cyan'
'Happy Happy Birthday'
'Amanda Gray'
'Gray Amanda'Arguments can be referenced by position starting at 0, or by keyword name.
8.3 Concatenating and Repeating Strings
The + operator joins strings. The * operator repeats a string.
s1 = 'happy'
s2 = 'birthday'
s1 += ' ' + s2
print(s1)
symbol = '>'
symbol *= 5
print(symbol)happy birthday
>>>>>+ to directly join a string and an integer. Convert the integer first, for example 'Age: ' + str(20).8.4 Stripping Whitespace from Strings
Whitespace includes spaces, tabs and newline characters. Python provides three useful methods for removing whitespace from the ends of a string.
| Method | Removes |
|---|---|
strip() | Leading and trailing whitespace |
lstrip() | Leading whitespace only |
rstrip() | Trailing whitespace only |
sentence = '\t \n This is a test string. \t\t \n'
print(sentence.strip())
print(sentence.lstrip())
print(sentence.rstrip())strip() is often one of the first cleaning steps.8.5 Changing Character Case
| Method | Purpose | Example |
|---|---|---|
lower() | All lowercase | 'Hello'.lower() → 'hello' |
upper() | All uppercase | 'Hello'.upper() → 'HELLO' |
capitalize() | First character capitalized | 'happy birthday'.capitalize() |
title() | First character of each word capitalized | 'strings: a deeper look'.title() |
print('happy birthday'.capitalize())
print('strings: a deeper look'.title())Happy birthday
Strings: A Deeper Look8.6 Comparison Operators for Strings
Strings can be compared with ==, !=, <, <=, > and >=. Python compares strings lexicographically using the underlying character values.
print(ord('A'))
print(ord('a'))
print('Orange' == 'orange')
print('Orange' != 'orange')
print('Orange' < 'orange')65
97
False
True
True'Python' and 'python' are different strings. If you want case-insensitive comparison, normalize the case first, for example with lower().8.7 Searching for Substrings
A substring is a sequence of adjacent characters inside a larger string.
Counting Occurrences
sentence = 'to be or not to be that is the question'
print(sentence.count('to'))
print(sentence.count('to', 12))
print(sentence.count('that', 12, 25))2
1
1Finding Positions
| Method | What it does when found | When not found |
|---|---|---|
index() | Returns first matching index | Raises ValueError |
rindex() | Returns last matching index | Raises ValueError |
find() | Returns first matching index | Returns -1 |
rfind() | Returns last matching index | Returns -1 |
sentence = 'to be or not to be that is the question'
print(sentence.index('be'))
print(sentence.rindex('be'))
print('that' in sentence)
print('THAT' not in sentence)
print(sentence.startswith('to'))
print(sentence.endswith('question'))3
16
True
True
True
Truein / not in when you only need to know whether a substring exists. Use find() when you need a position without an exception.8.8 Replacing Substrings
The replace() method searches for one substring and returns a new string in which matching occurrences are replaced.
values = '1\t2\t3\t4\t5'
print(values.replace('\t', ','))
print('one one one'.replace('one', 'two', 2))1,2,3,4,5
two two oneThe optional third argument limits how many replacements are performed.
8.9 Splitting and Joining Strings
When text is processed, we often break it into smaller pieces called tokens. Separators used to split data are often called delimiters.
Splitting
letters = 'A, B, C, D'
print(letters.split(', '))
print(letters.split(', ', 2))['A', 'B', 'C', 'D']
['A', 'B', 'C, D']split() without an argument separates on whitespace.
Joining
join() does the opposite: it combines an iterable of strings using the string on which join() is called as the separator.
letters_list = ['A', 'B', 'C', 'D']
print(','.join(letters_list))
print(','.join([str(i) for i in range(10)]))A,B,C,D
0,1,2,3,4,5,6,7,8,9join() must contain strings. If it contains integers, convert them with str().partition() and rpartition()
partition(separator) returns a tuple containing the part before the separator, the separator itself and the part after it.
result = 'Amanda: 89, 97, 92'.partition(': ')
print(result)
url = 'http://www.deitel.com/books/PyCDS/table_of_contents.html'
rest, separator, document = url.rpartition('/')
print(document)
print(rest)('Amanda', ': ', '89, 97, 92')
table_of_contents.html
http://www.deitel.com/books/PyCDSsplitlines()
splitlines() turns a multiline string into a list of lines.
lines = """This is line 1
This is line2
This is line3"""
print(lines.splitlines())
print(lines.splitlines(True))['This is line 1', 'This is line2', 'This is line3']
['This is line 1\n', 'This is line2\n', 'This is line3']8.10 Characters and Character-Testing Methods
Python does not have a separate character data type. A single character is simply a one-character string.
| Method | Returns True when... |
|---|---|
isalnum() | all characters are letters or digits |
isalpha() | all characters are letters |
isdecimal() | all characters are decimal digits |
isdigit() | all characters are digits |
isidentifier() | the string is a valid Python identifier |
islower() | alphabetic characters are lowercase |
isnumeric() | characters represent a numeric value |
isspace() | all characters are whitespace |
istitle() | each word has title-style capitalization |
isupper() | alphabetic characters are uppercase |
print('-27'.isdigit())
print('27'.isdigit())
print('A9876'.isalnum())
print('123 Main Street'.isalnum())
print('Hello'.isalpha())False
True
True
False
Trueisdigit() can be a simple first check.8.11 Raw Strings
Backslashes introduce escape sequences such as \n and \t. Windows file paths and regular expressions can contain many backslashes, which can make ordinary strings harder to read.
file_path = 'C:\\MyFolder\\MySubFolder\\MyFile.txt'
print(file_path)
file_path = r'C:\MyFolder\MySubFolder\MyFile.txt'
print(file_path)A raw string is written with an r before the opening quote. It treats backslashes as literal characters rather than starting ordinary escape sequences.
r'\d{5}'.8.12 Introduction to Regular Expressions
A regular expression is a string that describes a pattern. Instead of searching for one exact word, you can describe a whole family of strings.
Regular expressions are useful for phone numbers, e-mail addresses, ZIP Codes and other structured text. They can also extract information from unstructured text and help clean or transform data.
\d{5} does not mean "find these exact five characters." It means "find exactly five digit characters."8.12.1 re Module and Function fullmatch
Python's re module provides regular-expression functionality. re.fullmatch() checks whether the entire string matches a pattern.
import re
pattern = '02215'
print('Match' if re.fullmatch(pattern, '02215') else 'No match')
print('Match' if re.fullmatch(pattern, '51220') else 'No match')Match
No matchRegular-Expression Metacharacters
| Symbol | Basic idea |
|---|---|
[] | Custom character class |
{} | Number/range of repetitions |
() | Group and capture a subexpression |
\ | Escape or start predefined character classes |
* | Zero or more |
+ | One or more |
? | Zero or one |
^ | Beginning anchor or negation inside a class |
$ | End anchor |
. | Matches one character |
| | Alternation ("or") |
Predefined Character Classes
| Pattern | Meaning |
|---|---|
\d | Any digit, 0–9 |
\D | Any non-digit |
\s | Whitespace |
\S | Non-whitespace |
\w | Word character: letter, digit or underscore |
\W | Non-word character |
Custom Character Classes
print(re.fullmatch(r'[aeiou]', 'a'))
print(re.fullmatch(r'[A-Z]', 'G'))
print(re.fullmatch(r'[a-zA-Z]', 'z'))Examples:
[aeiou]— one lowercase vowel.[A-Z]— one uppercase letter.[a-z]— one lowercase letter.[^a-z]— one character that is not a lowercase letter.
Quantifiers
Quantifiers control how many times a pattern element can occur.
| Quantifier | Meaning | Example |
|---|---|---|
* | Zero or more | [a-z]* |
+ | One or more | [a-z]+ |
? | Zero or one | l? |
{n} | Exactly n | \d{5} |
{n,} | At least n | \d{3,} |
{n,m} | Between n and m inclusive | \d{3,6} |
print('Valid' if re.fullmatch(r'[A-Z][a-z]*', 'Wally') else 'Invalid')
print('Valid' if re.fullmatch(r'[A-Z][a-z]+', 'E') else 'Invalid')
print('Match' if re.fullmatch(r'\d{3,6}', '123456') else 'No match')
print('Match' if re.fullmatch(r'\d{3,6}', '1234567') else 'No match')Valid
Invalid
Match
No match\d{5}, then gradually learn classes, quantifiers, anchors and groups.8.12.2 Replacing Substrings and Splitting Strings
The re module's sub() function replaces text that matches a pattern. Its split() function tokenizes text using a regular-expression delimiter.
import re
print(re.sub(r'\t', ', ', '1\t2\t3\t4'))
print(re.sub(r'\t', ', ', '1\t2\t3\t4', count=2))
print(re.split(r',\s*', '1, 2, 3,4, 5,6,7,8'))
print(re.split(r',\s*', '1, 2, 3,4, 5,6,7,8', maxsplit=3))1, 2, 3, 4
1, 2, 3 4
['1', '2', '3', '4', '5', '6', '7', '8']
['1', '2', '3', '4, 5,6,7,8']8.12.3 Other Search Functions; Accessing Matches
| Function | Use |
|---|---|
search() | Find the first matching pattern anywhere in the string. |
match() | Search for a match at the beginning of the string. |
findall() | Find all matching substrings and return them in a list. |
finditer() | Find all matches and return a lazy iterable of match objects. |
import re
result = re.search('Python', 'Python is fun')
print(result.group() if result else 'not found')
result = re.search('fun$', 'Python is fun')
print(result.group() if result else 'not found')
contact = 'Wally White, Home: 555-555-1234, Work: 555-555-4321'
print(re.findall(r'\d{3}-\d{3}-\d{4}', contact))
for phone in re.finditer(r'\d{3}-\d{3}-\d{4}', contact):
print(phone.group())Python
fun
['555-555-1234', '555-555-4321']
555-555-1234
555-555-4321Ignoring Case
Regular expressions are case-sensitive by default. The re.IGNORECASE flag can make matching case-insensitive.
result = re.search('Sam', 'SAM WHITE', flags=re.IGNORECASE)
print(result.group() if result else 'not found')SAMBeginning and End Anchors
^ restricts a match to the beginning of a string, while $ restricts a match to the end.
print(re.search('^Python', 'Python is fun').group())
print(re.search('fun$', 'Python is fun').group())Python
funCapturing Substrings with Groups
Parentheses ( ) capture parts of a match. The resulting match object can provide the captured groups.
text = 'Charlie Cyan, e-mail: demo1@deitel.com'
pattern = r'([A-Z][a-z]+ [A-Z][a-z]+), e-mail: (\w+@\w+\.\w{3})'
result = re.search(pattern, text)
print(result.groups())
print(result.group())
print(result.group(1))
print(result.group(2))('Charlie Cyan', 'demo1@deitel.com')
Charlie Cyan, e-mail: demo1@deitel.com
Charlie Cyan
demo1@deitel.com1. group() or group(0) represents the complete match.8.13 Intro to Data Science: Pandas, Regular Expressions and Data Munging
Real-world data is often not ready for analysis. It may contain missing values, bad values, duplicates, inconsistent formats or unnecessary information.
Data Munging and Data Wrangling
Data munging and data wrangling refer to preparing data for analysis. Important work includes cleaning data and transforming it into useful formats.
| Problem | Possible action |
|---|---|
| Missing values | Delete, mark or carefully substitute values according to the situation. |
| Bad values | Correct at the source when possible or apply an appropriate cleaning strategy. |
| Duplicates | Remove duplicates when they are not valid observations. |
| Inconsistent formats | Standardize the representation. |
| Unnecessary features | Remove information that is not needed. |
| Different formats | Transform data into the format required by the application. |
Cleaning Example: Missing Temperature
Suppose a patient's temperature readings are:
['Brown, Sue', 98.6, 98.4, 98.7, 0.0]If 0.0 represents a missing sensor reading and is incorrectly treated as a real temperature, the calculated average becomes misleading. The chapter uses this example to show why missing and bad values must be handled carefully.
Validating Data with pandas and Regular Expressions
A pandas Series provides a str attribute with string-processing and regular-expression methods. This allows a pattern to be applied to an entire Series without explicitly writing a loop.
import pandas as pd
zips = pd.Series({
'Boston': '02215',
'Miami': '3310'
})
print(zips)
print(zips.str.match(r'\d{5}'))Boston 02215
Miami 3310
dtype: object
Boston True
Miami False
dtype: boolHere, \d{5} requires exactly five digits. Boston passes the test; Miami does not.
match() vs contains() in pandas
Use match() when the Series element itself must match the pattern. Use contains() when you want to know whether the value contains a substring matching the pattern.
cities = pd.Series([
'Boston, MA 02215',
'Miami, FL 33101'
])
print(cities.str.contains(r' [A-Z]{2} '))
print(cities.str.match(r' [A-Z]{2} '))0 True
1 True
dtype: bool
0 False
1 False
dtype: bool MA or FL , so contains() succeeds. But the complete value is not just MA or FL , so match() does not.Reformatting Data
The chapter also shows how regular expressions can transform 10-digit phone numbers into the format ###-###-####.
import re
def get_formatted_phone(value):
result = re.fullmatch(r'(\d{3})(\d{3})(\d{4})', value)
return '-'.join(result.groups()) if result else value
contacts = [
['Mike Green', 'demo1@deitel.com', '5555555555'],
['Sue Brown', 'demo2@deitel.com', '5555551234']
]
contactsdf = pd.DataFrame(
contacts,
columns=['Name', 'Email', 'Phone']
)
formatted_phone = contactsdf['Phone'].map(get_formatted_phone)
contactsdf['Phone'] = formatted_phone
print(contactsdf) Name Email Phone
0 Mike Green demo1@deitel.com 555-555-5555
1 Sue Brown demo2@deitel.com 555-555-1234fullmatch()checks for exactly 10 digits.- Parentheses capture three groups: first 3 digits, next 3 digits and last 4 digits.
groups()returns those captured pieces.join()puts-between them.- pandas
map()applies the function to every value in the Phone column.
Quick Concept Map
Common Mistakes
| Mistake | Correct idea |
|---|---|
Expecting strip() to modify the original string | Assign the returned string if you need to keep the cleaned value. |
Using index() when a substring may be absent | Use find() or handle the possible ValueError. |
Comparing 'A' and 'a' as equal | String comparison is case-sensitive. |
Passing integers to join() | Convert them to strings first. |
Forgetting that fullmatch() checks the entire string | Use search() when you need a match anywhere. |
Confusing match() and contains() in pandas | match() checks the complete value against the pattern; contains() checks for a matching substring. |
| Writing regex without understanding escapes | Use raw strings such as r'\d{5}' when appropriate. |
Remember These Points
- Strings are immutable.
+concatenates and*repeats strings.strip(),lstrip()andrstrip()remove whitespace from string ends.lower(),upper(),capitalize()andtitle()return new strings.inandnot inare simple substring-membership tests.find()returns-1when a substring is absent;index()raisesValueError.split()creates pieces;join()combines strings.- Raw strings make backslash-heavy text easier to write and read.
re.fullmatch()validates the whole string against a pattern.re.search()finds a pattern anywhere;findall()returns all matches.- Parentheses in regex can capture useful parts of a match.
- Regular expressions are useful for validation, extraction, cleaning and transformation.
- Data munging/wrangling prepares raw data for analysis.
Revision Questions
- Why are strings called immutable in Python?
- What is the difference between
strip(),lstrip()andrstrip()? - What is a substring?
- What is the difference between
find()andindex()? - How does
join()work? - What is a raw string and why is it useful for regular expressions?
- What does
\dmean in a regular expression? - What is the difference between
*and+in regex? - What does
{3,6}mean? - What is the difference between
re.fullmatch()andre.search()? - What do
^and$mean? - Why are parentheses used in a regular expression?
- What is data munging?
- In pandas, when would you use
str.match()and when would you usestr.contains()?
Practice Programs
1. Clean User Input
Ask the user for a name, remove surrounding whitespace and display it in title case.
2. Word Counter
Read a sentence, split it into words and display the number of words.
3. Phone Validator
Use re.fullmatch() to validate a phone number in the form 555-555-1234.
4. Extract Phone Numbers
Use re.findall() to extract every phone number from a paragraph.
5. Format Phone Numbers
Convert 10 consecutive digits into ###-###-#### using regex groups.
6. Data Cleaning
Create a pandas Series containing city and ZIP-code strings. Use str.match() and str.contains() to validate the data.
Chapter Wrap-Up
This chapter takes Python strings from basic text values to practical text-processing tools. You learned detailed string formatting, concatenation and repetition, whitespace removal, case conversion, comparisons, substring searching, replacement, splitting and joining, character testing and raw strings.
The chapter then introduces regular expressions through the re module. You learned how patterns, character classes, quantifiers, anchors and groups can be used to validate, search, extract, replace and split text.
Finally, the data-science section connects these ideas to pandas. Regular expressions can validate Series values and help transform messy real-world data into consistent formats. These skills prepare you for later work with files, CSV data and natural language processing.
Strings let you format → clean → compare → search → replace → split → join; regular expressions let you describe patterns; pandas lets you apply these ideas to data at scale.
Teaching edition note: This HTML is a beginner-friendly explanation based on the chapter's organization and concepts. It uses simplified explanations and original examples rather than reproducing the book verbatim.