Strings: A Deeper Look

A beginner-friendly teaching edition — concepts, examples, outputs, mistakes and revision
Big idea: Strings are sequences of characters. Python strings support many sequence operations, but strings are immutable: methods that appear to change a string actually return a new string. This chapter goes deeper into formatting, searching, splitting, character testing, raw strings and regular expressions.

What You Will Learn

  • Format string content with f-strings and the format method.
  • 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() and isalpha().
  • 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 Introduction8.2 Formatting StringsPresentation TypesField Width & AlignmentNumeric Formattingformat()8.3 Concatenating & Repeating8.4 Whitespace8.5 Character Case8.6 Comparisons8.7 Searching8.8 Replacing8.9 Splitting & Joining8.10 Character Testing8.11 Raw Strings8.12 Regular Expressions8.13 Pandas & Data Munging

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.

TextCleanSearchValidateTransformAnalyze
Why this matters: Text processing is important in applications such as search engines, chatbots, document classification, sentiment analysis, spell checking, web scraping and natural language processing.
Remember: Strings are immutable. If a method appears to modify a string, Python creates and returns a new string; the original string is not changed automatically.

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.

TypeMeaningExample
dIntegerf'{10:d}'
bBinary representation of an integerf'{10:b}'
oOctal representationf'{10:o}'
x / XHexadecimal representationf'{255:x}'
cCharacter represented by an integer codef'{65:c}'
sStringf'{"hello":s}'
fFixed-point floating-point formatf'{17.489:.2f}'
e / EScientific notationf'{1000:.2e}'
print(f'{17.489:.2f}')
print(f'{10:d}')
print(f'{65:c} {97:c}')
17.49
10
A a
Important: Precision such as .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    ]
SpecifierMeaning
<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
Quick pattern: : 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
>>>>>
Common mistake: You cannot use + 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.

MethodRemoves
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())
Real-world use: When user input or imported data contains accidental spaces or line breaks, strip() is often one of the first cleaning steps.

8.5 Changing Character Case

MethodPurposeExample
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 Look
Remember: These methods return new strings. They do not change the original string in place.

8.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
Case matters: '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
1

Finding Positions

MethodWhat it does when foundWhen not found
index()Returns first matching indexRaises ValueError
rindex()Returns last matching indexRaises ValueError
find()Returns first matching indexReturns -1
rfind()Returns last matching indexReturns -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
True
Easy choice: Use in / 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 one

The 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,9
Important: The iterable passed to join() 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/PyCDS

splitlines()

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.

MethodReturns 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
True
Validation example: If an input field should contain only digits, isdigit() 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.

Especially useful for: regular expressions, where backslashes are common, for example 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.

PatternMatchValidateExtractTransform

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.

Think of regex as a text rule:
\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 match

Regular-Expression Metacharacters

SymbolBasic 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

PatternMeaning
\dAny digit, 0–9
\DAny non-digit
\sWhitespace
\SNon-whitespace
\wWord character: letter, digit or underscore
\WNon-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.

QuantifierMeaningExample
*Zero or more[a-z]*
+One or more[a-z]+
?Zero or onel?
{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
Learning tip: Regex can feel harder than normal string methods at first. Start with small patterns such as \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

FunctionUse
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-4321

Ignoring 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')
SAM

Beginning 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
fun

Capturing 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.com
Group numbering: Captured groups are numbered from 1. 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.

Raw DataInspectCleanTransformAnalyze

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.

ProblemPossible action
Missing valuesDelete, mark or carefully substitute values according to the situation.
Bad valuesCorrect at the source when possible or apply an appropriate cleaning strategy.
DuplicatesRemove duplicates when they are not valid observations.
Inconsistent formatsStandardize the representation.
Unnecessary featuresRemove information that is not needed.
Different formatsTransform data into the format required by the application.
Important data-science lesson: Cleaning data is not simply "changing bad numbers until the result looks good." Decisions should be based on the data and the analysis requirements. Keep the original data whenever possible.

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: bool

Here, \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
Why? Each city string contains 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-1234
What happened?
  1. fullmatch() checks for exactly 10 digits.
  2. Parentheses capture three groups: first 3 digits, next 3 digits and last 4 digits.
  3. groups() returns those captured pieces.
  4. join() puts - between them.
  5. pandas map() applies the function to every value in the Phone column.

Quick Concept Map

StringsFormatCleanCompareSearchReplaceSplit / JoinRegexData Munging

Common Mistakes

MistakeCorrect idea
Expecting strip() to modify the original stringAssign the returned string if you need to keep the cleaned value.
Using index() when a substring may be absentUse find() or handle the possible ValueError.
Comparing 'A' and 'a' as equalString comparison is case-sensitive.
Passing integers to join()Convert them to strings first.
Forgetting that fullmatch() checks the entire stringUse search() when you need a match anywhere.
Confusing match() and contains() in pandasmatch() checks the complete value against the pattern; contains() checks for a matching substring.
Writing regex without understanding escapesUse raw strings such as r'\d{5}' when appropriate.

Remember These Points

  • Strings are immutable.
  • + concatenates and * repeats strings.
  • strip(), lstrip() and rstrip() remove whitespace from string ends.
  • lower(), upper(), capitalize() and title() return new strings.
  • in and not in are simple substring-membership tests.
  • find() returns -1 when a substring is absent; index() raises ValueError.
  • 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

  1. Why are strings called immutable in Python?
  2. What is the difference between strip(), lstrip() and rstrip()?
  3. What is a substring?
  4. What is the difference between find() and index()?
  5. How does join() work?
  6. What is a raw string and why is it useful for regular expressions?
  7. What does \d mean in a regular expression?
  8. What is the difference between * and + in regex?
  9. What does {3,6} mean?
  10. What is the difference between re.fullmatch() and re.search()?
  11. What do ^ and $ mean?
  12. Why are parentheses used in a regular expression?
  13. What is data munging?
  14. In pandas, when would you use str.match() and when would you use str.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.

One-line memory:
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.