Strings as a Compound Data Type - Review

Indexing

What is the index of the following characters in these strings? →

  1. 'h' in "hi bob!"
  2. '!' in "hi bob!"
  3. ' ' in "hi bob!"
1. 0
2. 6
3. 2

Indexing Continued

What's the output of the following code? →

idx, animal = -2, "tiger"
print(animal[-1])
print(animal[idx])
print("animal"[2])
print(animal[idx + 2])
print(animal[idx + 100])
r
e
i
t
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

Summary for Indexing

Indexing Syntax

The indexing syntax is as follows:

Indexing Examples

# index into string that's bound to a variable name
a = "foo"
a[0]
# index into a string literal
"foo"[0]
# index into the return result of a function
def give_back_foo():
	return "foo"

give_back_foo()[0]

Are Strings Mutable?

What happens if I try to change the string "pugs" into "hugs" using inexing and the assignment operator? →

"hugs"[0] = 'p'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

An Index That Doesn't Exist

What happens if I try to access an index that doesn't exist? →

word = "pugs"
print(word[50])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of ranges

Using Every Character in a String

What if we want to do something to each character in a string?

Looping Over Each Character

We can iterate over every character that's in a string.

# for loops!
for c in "hello":
  print(c)

For Loops and Strings

my_crazy_string = "oh my!"
for c in my_crazy_string:
  print(c)
o
h
 
m
y
!

Another Example

The following code:

word = "jetpack"
suffix = "am"
for c in word:
	print(c + suffix)

A Quick Aside on Assert

assert <some expression that results in a bool>, <a string>
assert expected == actual, "describe test"

A Quick Aside on Break

The break statement immediately stops the execution of a loop. What does the following code print out? →

for letter in "challenge":
	if letter == 'a':
		break
	print(letter + "at")
cat
hat

A Quick Aside on Docstrings

A docstring is a triple-quoted string immediately following the header of a function definition.

def foo()
	"""gives back a greeting"""
	return "hi"

Letter in Word (v1)

Try implementing this function!

Letter in Word (v1) Continued

def letter_in_word(letter, word):
	""" determines whether or not a letter is in a word"""
	for c in word:
		if c == letter:
			return True
	return False

assert True == letter_in_word('x', "ox"), "letter is in word"
assert False == letter_in_word('y', "ox"), "letter is not in word"

Letter in Word (v2)

Here's another way of doing it using break.

def letter_in_word(letter, word):
	result = False
	for c in word:
		if c == letter:
			result = True
			break
	return result

assert True == letter_in_word('c', "chihuahua"), "letter is in word"
assert False == letter_in_word('x', "chihuahua"), "letter is not in word"

Letter in Word Revisited

There are actually a couple of much easier ways to do this rather than writing our own function. What are two ways of determining whether or not a string is a substring of another string?

# use the in operator:
'a' in 'aardvark'

# use the find method:
'aardvark'.find('a')

Looping Over Strings Summary / Syntax

How Many A's Are in Aardvark?

Write a function that counts how many times a letter occurs in a word. →

>>> print(count_letters('a', 'aardvark'))
3

How Many A's Are in Aardvark? Solution

def count_letters(letter, word):
	"""returns the number of times a letter occurs in a word"""
	count = 0
	for c in word:
		if c == letter:
			count += 1
	return count
assert 3 == count_letters("a", "aardvark"), "should count letters in word"
assert 0 == count_letters("x", "aardvark"), "zero if no letters in word"

Counting letters Revisited

Just like finding a substring, there's a much easier way to find the number of times a substring occurs inside another string. What is the method that let's us do this?

# it's just count!
"banana".count('an')

Construct a String With Spaces After Every Letter

Let's write a function that takes a string and puts a space after every character. →

>>> print(insert_spaces('aaaah!'))
a a a a h ! 

Construct a String With Spaces After Every Letter Solution

def insert_spaces(word):
    """inserts spaces after every letter in word"""
    new_word = ""
    for c in word:
        new_word += c + " " 
    return new_word
assert "f i s h " == insert_spaces("fish"), "inserts spaces after every letter"
assert "" == insert_spaces(""), "empty string if word is empty"
print(insert_spaces("fish"))

Slicing

You can also retrieve a substring from another string.

This is done using slicing. Slicing syntax works as follows:

>>> "placate"[3:6]
'cat'

Slicing Syntax

Looking at the slicing code again:

>>> "placate"[3:6]
'cat'

The general case is:

some_long_string[m:n]

Substring Exercises

Write the slice to pick out the following substring from the original string:

s = "gone!"
#    01234
  1. go
  2. on
  3. one
  4. one!
s[0:2]
s[1:3]
s[1:4]
s[1:5]

Some Slicing Tricks

"eggs and ham"[:4] #eggs
"eggs and ham"[9:] #ham
"eggs and ham"[9:100] #ham

An Easier Way to Tell if a Letter is in a Word

Use the in operator!

In Examples

>>> word = "ice cream"
>>> letter = "a"
>>> letter in word
True
>>> "cat" in "vacation"
True
>>> "cat" in "work"
False
>>> 

In / Not In

Some other things to note:

A string is always a substring of itself.

>>> "vacation" in "vacation"
True

Empty string is always a substring of any other string.

>>> "" in "vacation"
True

not in is the logical opposite of the in operator

>>> "cat" not in "vacation"
False

First Word in a Sentence

Create a function that returns the first word in a sentence.

First Word in a Sentence Potential Solution

def get_first_word(sentence):
	"""returns the first word in a sentence"""
	index = 0
	for c in sentence:
		if c == " ":
			break
		index += 1
	return sentence[0:index]

assert "hi" == get_first_word("hi there!"), "returns first word"
assert "hi" == get_first_word("hi"), "returns word if only one word"
assert "" == get_first_word("  "), "returns empty if only white space"
assert "" == get_first_word(""), "returns empty if sentence is empty"
# print(get_first_word("hi there!"))
# print(get_first_word("hi"))

Is Digit?

Create a function that determines whether or not a string only has numbers (0-9) in it.

Is Digit? Potential Solution

def is_digit(s):
	"""determines if a string is numeric (only contains 0 through 9)"""
	if s == "":
		return False

	for c in s:
		if c not in "0123456789":
			return False

	return True

assert True == is_digit("58723"), "true of all characters are numeric "
assert False == is_digit("twelve"), "false if not all characters are numeric"
assert False == is_digit("12 ducks"), "false if not all characters are numeric"
assert False == is_digit(""), "false if empty string"
# print(is_digit("43"))

Is Digit Revisited

And of course, there's already a couple of methods that do this. What are they?

"123".isdigit()
"123".isnumeric()
"abc".isdigit()
"abc".isnumeric()