BYU logo Computer Science

To start this guide, download this zip file.

Substrings

When working with strings, you often want to manipulate substrings, meaning a piece of the string.

'amazing' is a substring of 'yesterday i read an amazing book'

Replacing substrings

You can use the replace() function to replace a substring with another substring. For example:

text = 'Yesterday I read an amazing book.'
new_text = text.replace('amazing', 'intriguing')
print(new_text)

This will print:

Yesterday I read an intriguing book.

Remember, a string is just a sequence of characters, so this isn’t only for replacing words:

text = 'Yesterday I read an amazing book.'
new_text = text.replace(' ', '-')
print(new_text)

This prints:

Yesterday-I-read-an-amazing-book.

Or:

text = 'Yesterday I read an amazing book.'
new_text = text.replace('n amazing', ' sad')
print(new_text)

This prints:

Yesterday I read a sad book.

Limited replacement

By default, replace() will replace all occurrences of the substring. You can limit this by adding a third parameter. For example, let’s say you want to replace the first space with a comma and a space:

text = 'Yesterday I read an amazing book.'
new_text = text.replace(' ', ', ', 1)
print(new_text)

This prints:

Yesterday, I read an amazing book.

Or maybe:

text = 'The villain laughed: "HAHAHAHAHA"'
text = text.replace('HA', 'ha', 3)
print(text)

This prints:

The villain laughed: "hahahaHAHA"

You can find all the substring replacement examples in replacing_substrings.py.

Checking for a substring

You can check whether a substring is present in a string using in. This results in very natural syntax:

if 'BYU' in 'I am a student at BYU.':
    print('Hurray!')
else:
    print('Boo!')

This prints:

Hurray!

Likewise:

if 'BYU' in 'This room is full of monkeys!':
    print('Hurray!')
else:
    print('Boo!')

This prints:

Boo!

Custom character classes

Using in allows us to create custom character classes. For example, here is a function that returns True if a letter is a vowel:

def is_vowel(letter: str) -> bool:
    return letter in 'AEIOUaeiou'

We can use this in the following code:

if __name__ == '__main__':
    found = ''
    for letter in 'The Aeneid is ancient Greek literature.':
        if is_vowel(letter):
            found += letter
    print(found)

You can find this code in collect_vowels.py. This code prints:

eAeeiiaieeeieaue

Let’s write a function that capitalizes every letter of a string that is a part of “BYU”:

def byu(text: str) -> str:
    """Capitalize every letter of `text` that is part of 'BYU'"""
    result = ''
    for c in text:
        if c in 'byu':
            result += c.upper()
        else:
            result += c
    return result

Now we can call this:

if __name__ == '__main__':
    print(byu('Any student, boy or girl, young or old, can be a yodeler.'))

You can find this code in capitalize_byu.py. This prints:

AnY stUdent, BoY or girl, YoUng or old, can Be a Yodeler.

Early return

Using in works well with a pattern called early return. For example, here is a function that checks whether a string has brackets in it:

def is_bracket(letter: str) -> bool:
    return letter in '{}[]<>'

def has_brackets(text: str) -> bool:
    for letter in text:
        if is_bracket(letter):
            return True
    return False

Notice that in has_bracket(), as soon as we find a bracket, we can return True. We don’t have to loop through the rest of the characters. By default, if we loop through all characters and don’t find the bracket, then we return False.

We can call it:

if __name__ == '__main__':
    print(has_brackets('Just some words'))
    print(has_brackets('A Python list prints like this: [1, 2, 3, 4]'))

You can find this code in has_brackets.py. Running it will print:

False
True

Odd numbers

Write a function that indicates whether a string has odd-numbered digits in it.

Work with a friend to write this code. You can find starter code in odd_numbers.py.

work with a friend to solve this problem

Here is a solution:

def is_odd_digit(letter: str) -> bool:
    return letter in '13579'


def has_odds(text: str) -> bool:
    """Return True if the text has odd-numbered digits"""
    for letter in text:
        if is_odd_digit(letter):
            return True
    return False


def main():
    print(has_odds('I have 2 apples to share with 4 people.'))
    print(has_odds('I have 2 apples, and there are 3 people, but I will eat them all!'))


if __name__ == '__main__':
    main()

Notice that we use the early return pattern in has_odds().

This prints:

False
True

True blue

Write a function that indicates whether a text has any of the following substrings in it:

  • BYU
  • blue
  • cougar

Work with a friend to write this code. You can find starter code in true_blue.py.

work with a friend to solve this problem

Here is a solution:

def is_true_blue(text: str) -> bool:
    """Returns True if `text` contains any of: 'BYU', 'blue', or 'cougar'"""
    for word in ['BYU', 'blue', 'cougar']:
        if word in text:
            return True
    return False


def main():
    print(is_true_blue('My friend goes to UVU'))
    print(is_true_blue('I love BYU!'))
    print(is_true_blue('The sky is blue'))


if __name__ == '__main__':
    main()

This prints:

False
True
True

In with lists

We can also use in with lists:

def is_suspect(person: str) -> bool:
    return person in ['John', 'Jane', 'Susan', 'Carlos', 'Kathy', 'Morgan']

This function returns True if the person supplied as the parameter is one of the strings in the list of strings ['John', 'Jane', 'Susan', 'Carlos', 'Kathy', 'Morgan'].

Here is how we can use it:

def identify_suspects(people: str) -> list[str]:
    suspects = []
    for person in people:
        if is_suspect(person):
            suspects.append(person)
    return suspects


if __name__ == '__main__':
    students = ['George', 'Hannah', 'Kathy', 'Michael', 'John']
    print(identify_suspects(students))
    neighbors = ['Carl', 'Brooke', 'Jane', 'Jarom', 'Sally', 'John', 'Mike']
    print(identify_suspects(neighbors))

In identify_suspects(), we take a list of names, loop over them, and return a new list that has only the names that are suspects.

You can find this code in identify_subjects.py. When you run it, it prints:

['Kathy', 'John']
['Jane', 'John']

Multiple comparisons

This is extra material

What if we want to find a suspected student who is also a neighbor? Here is a function that takes a list of students and a list of neighbors and finds the suspects who are also neighbors:

def find_key_suspects(students: list[str], neighbors: list[str]) -> list[str]:
    suspected_students = identify_suspects(students)

    key_suspects = []
    for person in suspected_students:
        if person in neighbors:
            key_suspects.append(person)
    return key_suspects

We can use this function this way:

def is_suspect(person: str) -> bool:
    return person in ['John', 'Jane', 'Susan', 'Carlos', 'Kathy', 'Morgan']


def identify_suspects(people: list[str]) -> list[str]:
    suspects = []
    for person in people:
        if is_suspect(person):
            suspects.append(person)
    return suspects


def find_key_suspects(students: list[str], neighbors: list[str]) -> list[str]:
    suspected_students = identify_suspects(students)

    key_suspects = []
    for person in suspected_students:
        if person in neighbors:
            key_suspects.append(person)
    return key_suspects


if __name__ == '__main__':
    students = ['George', 'Hannah', 'Kathy', 'Michael', 'John']
    neighbors = ['Carl', 'Brooke', 'Jane', 'Jarom', 'Sally', 'John', 'Mike']
    print(find_key_suspects(students, neighbors))

You can find this code in identify_suspect_neighbors.py. When you run it, it prints:

['John']

There are other ways to solve this problem! You could also take the list of students and filter out any that are not neighbors, using the filter pattern, then find suspects:

def is_suspect(person: str) -> bool:
    return person in ['John', 'Jane', 'Susan', 'Carlos', 'Kathy', 'Morgan']


def filter_to(population: list[str], group: list[str]):
    keepers = []
    for item in population:
        if item in group:
            keepers.append(item)
    return keepers


def identify_suspects(people: list[str]) -> list[str]:
    suspects = []
    for person in people:
        if is_suspect(person):
            suspects.append(person)
    return suspects


def find_key_suspects(students: list[str], neighbors: list[str]) -> list[str]:
    student_neighbors = filter_to(students, neighbors)
    key_suspects = identify_suspects(student_neighbors)
    return key_suspects


if __name__ == '__main__':
    students = ['George', 'Hannah', 'Kathy', 'Michael', 'John']
    neighbors = ['Carl', 'Brooke', 'Jane', 'Jarom', 'Sally', 'John', 'Mike']
    print(find_key_suspects(students, neighbors))

This code is in identify_suspect_neighbors_alternate.py.