Strings

String Literals

A string literal can normally be specified by enclosing it within a pair of '' or a pair of "" e.g., 'How is life?'. However, this will not work if the string has a special character in it e.g., 'How's life?' is not acceptable to Python because it contains a ' which has the special meaning 'end of string', confusing Python as to which ' of the string literal indicates the end of the string. This is similarly confusing: "Say "wow"".

An escape sequence is a sequence of characters in a string literal that is taken together and interpreted in a special way. You can use an escape sequence to include a special character in a string literal without interpreting it as a special character. Given below are some examples:

Escape Sequence Meaning Example Output
\' single quote print('How\'s Life') How's Life?
\" double quote print("Say \"wow\"") Say "wow"
\\ back slash print('files\\text') files\text

Another use of escape sequences is to give a special meaning to a character that normally does not have a special meaning. Here are some examples:

Escape Sequence Meaning Example Output
\t horizontal tab print('aaa\tbbb') aaa bbb
\n line break print('hi\nthere!') hi
there!

Exercise : Escape Sequences

Modify the get_string() function so that the code prints the given output.
Note that these words are separated by tabs, not normal spaces:"oops"{tab here}"ok" {tab here}"oh?"

def get_string():
  return '' # REPLACE WITH YOUR CODE

print(get_string())

⤵️

Which word didn't he/she say? ["oops" "ok" "oh?"]
  • Use \t to print a tab character.
  • Use \' to print a single quote inside a string.
def get_string():
  return 'Which word didn\'t he/she say? ...'

print(get_string())

You can use a pair of triple quotes to indicate a multi-line string literal.

📦 Here is an example multi-line string that uses triple quotes.

print('''Hi,
How's life?
bye!
-me''')


 → 

Hi,
How's life?
bye!
-me

def get_email_body():
  body = '''This is the first line of the email.
This is the second line.
This is the third line.
          - bye!'''
  return body

print(get_email_body())





 → 




This is the first line of the email.
This is the second line.
This is the third line.
          - bye!

It is optional to escape ' and " inside a mult-line string within triple quotes e.g., How's life? in the example above.

Exercise : Multi-Line String

Modify the get_multiline_string() function so that the code prints the given output exactly as given.

def get_multiline_string():
  return '' #REPLACE WITH YOUR CODE
    
print(get_multiline_string()) 

⤵️

Which word didn't he/she say?
* "oops"
  * "ok"
    * "oh?"
  • Use ''' to indicate multi-line strings.
return '''Which word didn't he/she say?

'''

Triple double-quotes (""") are commonly used to show documentation of code. Such comments are called docstrings.

📦 The remove_head(items) function below has a docstring that explains its behavior.

def remove_head(items):
  """Remove the first item of the items.

  The list should have at least one item.
  Arguments:
  items -- (type: list) the list of items to be modified
  """
  print('removing head of list ', items)
  del items[0]

📎 Vist this page to learn more about docstrings



Working with Strings

As you have seen before, you can use + and * operators to concatenate and replicate strings
e.g., 'abc' + '!'*5 evaluates to 'abc!!!!!'.

You can use indexes and slices to access characters of a string, just like if a string is a simply a list of characters.

i.e., 'Hi there' is same as a list:

H i t h e r e !
0 1 2 3 4 5 6 7 8

📦 The code below shows how to use index and slice notations to get parts of a string.

s = 'Hi there!'
print(s[0])
print(s[-1])
print(s[3:6])



 → 


H
!
the

❗️ Strings are immutable. The following code will not work: s[0] = 'h'

Exercise : Shorten String

Complete the function given below, to behave as described by its docstring.

def shorten(text):
  """ Return a 10-character version of the string if it is longer.
  
  If text is longer than 10 characters, return the first four characters 
  followed by '..' followed by the last four characters.
  If text is not longer than 10 characters, returns text.
  
  Example:
  shorten('1234567890abcd') returns '1234..abcd'
  """
  pass # REPLACE WITH YOUR CODE

Example usage:

print(shorten('1234'))    
print(shorten('1234567890'))
print(shorten('1234567890abcd'))


 → 

1234
1234567890
1234..abcd

  if len(text) > 10:
    return text[:4] + '..' # ...
  else:
    return text

You can use the in and not in operator to see if one string is a sub-string of another.

📦 Examples of checking for the existence of a sub-string:

s = 'Hi there!'
print('Hi' in s)
print('hi' in s) # matching is case-sensitive
print('Hello' not in s)



 → 


True
False
True

Exercise : Has All Characters

Complete the function given below so that it returns True if text has all the characters in the list characters.

def has_all_characters(text, characters):
  #pass # REPLACE WITH YOUR CODE

Example usage:

print(has_all_characters('abccde', ['a', 'c']))
print(has_all_characters('ab cde', ['a', 'a', ' ']))
print(has_all_characters('apple', ['a', 'f']))


 → 

True
True
False

def has_all_characters(text, characters):
  for c in characters:
    if ...
      return False
  return True



String Methods

String objects have many methods (the full list is here).

Here are some string methods related to the nature of the string.

  • upper(): returns a string with all characters in upper case
  • lower(): returns a string with all characters in lower case
  • isupper(): returns True if all characters are in upper case
  • islower(): returns True if all characters are in lower case
  • isalpha(): returns True if the string consists only of letters and is not blank.
  • isalnum(): returns True if the string consists only of letters and numbers and is not blank.
  • isdecimal(): returns True if the string consists only of numeric characters and is not blank.
  • isspace(): returns True if the string consists only of spaces, tabs, and new-lines and is not blank.
  • startswith(s): returns True if the substring s appears at the start of the string
  • endswith(s): returns True if the substring s appears at the end of the string

📦 Examples of string methods mentioned above:

print('Hi there!'.upper())
print('Hi there!'.lower())


 → 

HI THERE!
hi there!

print('ABC'.isupper(), 'Abc'.isupper())
print('abc'.islower(), 'Abc'.islower())
print('abc'.isalpha(), 'A12'.isalpha())
print('A23'.isalnum(), 'A+1'.isalnum())
print('123'.isdecimal(), 'A12'.isdecimal())
print(' \t\n'.isspace(), 'a b'.isspace())


 → 

True False
True False
True False
True False
True False
True False

s = 'Hi there!'
print(s.startswith('Hi'), s.startswith('hi'))
print(s.endswith('!'), s.endswith('?'))



 → 


True False
True False

Exercise : Rectify Case

Complete the rectify_case(text) function given below, to behave as follows:

  • If text is all upper case, return text in lower case
  • If text is all lower case, return text in upper case
  • Return text otherwise
def rectify_case(text):
  #pass # REPLACE WITH YOUR CODE

Example usage:

print(rectify_case('Mrs. Fox'))
print(rectify_case('MR. FOX'))
print(rectify_case('baby fox'))


 → 

Mrs. Fox
mr. fox
BABY FOX

  if text.isupper(): 
    return text.lower()
  ...

Exercise : Is Doctor

Complete the is_doctor(name) function to return True for the following cases:

  • If name has a Dr. at the start
  • If name has a (Dr) at the end

Note that the matching should be case-insensitive.

def is_doctor(name):
  #pass # REPLACE WITH YOUR CODE

Example usage:

print(is_doctor('Dr. Jekyll'))
print(is_doctor('DR. Jekyll'))
print(is_doctor('dR. Jekyll'))
print(is_doctor('dr. Jekyll'))
print(is_doctor('Jekyll (Dr)'))
print(is_doctor('Jekyll (DR)'))
print(is_doctor('Jekyll (dr)'))
print(is_doctor('Mr. Hyde'))
print(is_doctor('Miss Dr. B.more'))


 → 

True
True
True
True
True
True
True
False
False

Convert the name to lower case and match with dr. or (dr) using string methods startswith()/endswith()

  name = name.lower()
  return name.startswith('dr.') ...

The find(s) method gives index of s in the string, if it is found. It returns -1 if s is not found.

📦 Examples of the find() method:

s = 'Monty Python'
print(s.find('Monty'))
print(s.find('Python'))
print(s.find('Spam'))



 → 


0
6
-1

Exercise : Remove From Word

Complete the remove_from_word(text, word) function given below, to behave as follows:

  • If word is found in text, return text minus the word (its first appearance) and any characters that appears after the word
  • Return text otherwise
def remove_from_word(text, word):
  #pass # REPLACE WITH YOUR CODE

Example usage:

print('>' + remove_from_word('red-hot-lava', 'red'))
print('>' + remove_from_word('red-hot-lava', 'hot'))
print('>' + remove_from_word('red-hot-lava', 'lava'))
print('>' + remove_from_word('red-hot-lava', 'bat'))
print('>' + remove_from_word('red-hot-lava', '-'))


 → 

>
>red-
>red-hot-
>red-hot-lava
>red

def remove_from_word(text, tail_start_word):
  tail_start_position = text.find(tail_start_word)
  if tail_start_position != -1:
    return ...
  else:
    return ...

The join() method joins a list of string items while using the target string object as a delimiter.

📦 Examples of the join() method:

print(', '.join(['tom', 'dick', 'harry']))
print('-'.join(['one', 'to', 'one']))


 → 

tom, dick, harry
one-to-one

The split() method is the opposite of join(). It splits a string into a list of strings based on a given delimiter string. If no delimiter is given, any whitespace in the string are used as delimiters.

📦 Some examples of using the split() method:

print('hi, how are you?'.split())
print('A1\t\tA2\nA3'.split())
print('''Todo:
1. eat
2. sleep'''.split('\n')) # split into lines
print('1-to-1-talk'.split('-'))




 → 



['hi,', 'how', 'are', 'you?']
['A1', 'A2', 'A3']
['Todo:', '1. eat', '2. sleep']
['1', 'to', '1', 'talk']

There are some string methods to help you to strip trailing/leading spaces.

📦 Examples of stripping leading/trailing spaces from a string:

s = '  hello  there!  '
print('['+ s.strip() + ']')
print('['+ s.lstrip() + ']') #left side strip
print('['+ s.rstrip() + ']') #right side strip



 → 


[hello  there!]
[hello  there!  ]
[  hello  there!]

Exercise : Get Part

Complete the get_part(text, index) function given below, to behave as follows:

  1. Split text using | as the delimiter
  2. Return the part indicated by the index

The return value should not have leading/trailing spaces.

def get_part(text, index):
  #pass # REPLACE WITH YOUR CODE

Example usage:

print(get_part(' John Doe | Male |    X', 0))
print(get_part('John Doe | Male |    X', 2))
print(get_part('Dog|Cat', 0))


 → 

John Doe
X
Dog

return text.split('|')...

The replace() method can replace a character (or a phrase) with another character/phrase.

📦 Some examples of using replace() method:

print('face to face'.replace(' ', '-'))  # replace space with a dash
print('1,2,3,4'.replace(',', '\t'))  # replace comma with a tab
print('Yup, Yup, I agree'.replace('Yup', 'Yes'))

⤵️

face-to-face
1	2	3	4
Yes, Yes, I agree

There are some string methods to help you to align text.

📦 Examples of aligning text using string methods:

print('Here:'.rjust(20, '>')) # right-justify
print('Price'.ljust(20, '=')) # left-justify
print('Title'.center(20, ':')) # center


 → 

>>>>>>>>>>>>>>>Here:
Price===============
:::::::Title::::::::

Exercise : Print Formatted Item

Complete the print_formatted_item(name, count, width) function given below, to behave as follows:

  • Print name and count in the format name.................: count
  • Width used for printing should be width (counted in number of characters)
  • Use 3 spaces for count i.e., assume count is 0..999
  • Left-justify the name and right-justify the count
  • Replace any square brackets [] in the name with normal brackets ()
def print_formatted_item(name, count, width):
  print('') # REPLACE WITH YOUR CODE

Example usage:

w = 25
print_formatted_item('pens', 2, w)
print_formatted_item('books[old]', 50, w)
print_formatted_item('pins[new]', 110, w)



 → 


pens.................:  2
books(old)...........: 50
pins(new)............:110

w = 20
print_formatted_item('pens', 2, w)
print_formatted_item('books[old]', 50, w)
print_formatted_item('pins[new]', 110, w)



 → 


pens............:  2
books(old)......: 50
pins(new).......:110

def print_formatted_item(name, count, width):
  name = name.replace('[', '(').replace(...)
  print(name.ljust(width-4, '.') + ...)

Exercise : Inventory Report

Write a function that prints an inventory report like the examples given below, when the report title (a string), print-width (an int), and list of items (as a suitable data structure, e.g., dictionary) is given to the function.

📦 Kitchen Inventory Report:

  • Title: Kitchen
  • Width: 15
Item count
pots 5
eggs 100

 → 
###############
### KITCHEN ###
###############
eggs.......:100
pots.......:  5
            ---
total......:105
            ===

📦 Bookshop Inventory Report:

  • Title: Book Shop
  • Width: 25
Item count
pens 85
books 3
pencils 22

 → 
#########################
####### BOOK SHOP #######
#########################
books................:  3
pencils..............: 22
pens.................: 85
                      ---
total................:110
                      ===

  • Title should be centered and in upper case.
  • Items should be in alphabetical order.
  • Width of the number column is 3. Numbers should be right-justified.
def print_inventory(items, title, width):
  print_header(width, title)
  for k in sorted(items.keys()):
    print_item(k, items[k], width)
  print_total(calculate_total(items), width)


def print_header(width, title):
  """ print the given title in the format of a banner.
  
  Example: print_header(10, 'hi')
  ##########
  ### HI ###
  ##########
  
  * The title is center aligned and in upper case
  
  Arguments:
  word -- (type:string) the title of the banner
  width -- (type:int) the width of the banner
  """
  print('#'*width)
  # ADD YOUR CODE HERE
  
  
def print_total(total, width):
  """ print the given total in the following format
  
  Example: print_total(5, 12)
           ---
  total...:  5
           ===
  
  * The total is right-justified
  
  Arguments:
  total -- (type:int) the total to print
  width -- (type:int) the width to use for printing
  """
  print('---'.rjust(width, ' '))
  # ADD YOUR CODE HERE
  
  
def print_item(name, count, width):
  """ Print the name and count as a row in the inventory listing.
  
  Example: print_item('pins', 2, 12)
  pins....:  2
  
  * The count is right-justified in a column that is 3 characters wide. 
  
  Arguments:
  name -- (type:string) name of the item
  count -- (type:int) number of items
  width -- (type:int) the width to use for printing
  """
  pass #  REPLACE WITH YOUR CODE

  
def calculate_total(items):
  total = 0
  for v in items.values():
    total = total + v
  return total  
  
print_inventory({'pots':5, 'eggs':100}, 'Kitchen', 15)
print('\n')
print_inventory({'pens': 85, 'books': 3, 'pencils': 22}, 'Book Shop', 25)