Homework 9: Regular Expressions

Due by 11:59pm on Thursday, November 18


Download hw09.zip.

Submission: When you are done, submit with python3 ok --submit. You may submit more than once before the deadline; only the final submission will be scored. Check that you have successfully submitted your code on okpy.org. See Lab 0 for more instructions on submitting assignments.

Using Ok: If you have any questions about using Ok, please refer to this guide.

Grading: Homework is graded based on correctness. Each incorrect problem will decrease the total score by one point. There is a homework recovery policy as stated in the syllabus. This homework is out of 2 points.



Q1: What would RegEx Match?

For each of the following regular expressions, suggest a string that would be fully matched.

Use Ok to test your knowledge by choosing the best answer for each of the following questions:

python3 ok -q wwrm -u

Q2: Roman Numerals

Write a regular expression that finds any string of letters that resemble a Roman numeral and aren't part of another word. A Roman numeral is made up of the letters I, V, X, L, C, D, M and is at least one letter long.

For the purposes of this problem, don't worry about whether or not a Roman numeral is valid. For example, "VIIIII" is not a Roman numeral, but it is fine if your regex matches it.

import re

def roman_numerals(text):
    Finds any string of letters that could be a Roman numeral
    (made up of the letters I, V, X, L, C, D, M).

    >>> roman_numerals("Sir Richard IIV, can you tell Richard VI that Richard IV is on the phone?")
    ['IIV', 'VI', 'IV']
    >>> roman_numerals("My TODOs: I. Groceries II. Learn how to count in Roman IV. Profit")
    ['I', 'II', 'IV']
    >>> roman_numerals("I. Act 1 II. Act 2 III. Act 3 IV. Act 4 V. Act 5")
    ['I', 'II', 'III', 'IV', 'V']
    >>> roman_numerals("Let's play Civ VII")
    >>> roman_numerals("i love vi so much more than emacs.")
    >>> roman_numerals("she loves ALL editors equally.")
    return re.findall(__________, text)

Use Ok to test your code:

python3 ok -q roman_numerals

Q3: CS Classes

On reddit.com, there is an /r/berkeley subreddit for discussions about everything UC Berkeley. However, there is such a large amount of CS-related posts that those posts are auto-tagged so that readers can choose to ignore them or read only them.

Write a regular expression that finds strings that resemble a CS class- starting with "CS", followed by a number, and then optionally followed by "A", "B", or "C". Your search should be case insensitive, so both "CS61A" and "cs61a" would match.

import re

def cs_classes(post):
    Returns strings that look like a Berkeley CS class,
    starting with "CS", followed by a number, optionally ending with A, B, or C
    and potentially with a space between "CS" and the number.
    Case insensitive.

    >>> cs_classes("Is it unreasonable to take CS61A, CS61B, CS70, and EE16A in the summer?")
    >>> cs_classes("how do I become a TA for cs61a? that job sounds so fun")
    >>> cs_classes("Can I take ECON101 as a CS major?")
    >>> cs_classes("Should I do the lab lites or regular labs in EE16A?")
    >>> cs_classes("What are some good CS upper division courses? I was thinking about CS 161 or CS 169a")
    return bool(re.search(__________, post))

Use Ok to test your code:

python3 ok -q cs_classes

Q4: Time for Times

You're given a body of text and told that within it are some times. Write a regular expression which, for a few examples, would match the following:

['05:24', '7:23', '23:59', '12:22', '00:00']

but would not match these invalid "times"

['05:64', '70:23']

You may find non-capturing groups helpful to use for this question.

import re

def match_time(text):
    >>> match_time("At 05:24AM, I had sesame bagels with cream cheese before my coffee at 7:23.")
    ['05:24AM', '7:23']
    >>> match_time("At 23:59 I was sound asleep as the time turned to 00:00.")
    ['23:59', '00:00']
    >>> match_time("Mix water in a 1:2 ratio with chicken stock.")
    >>> match_time("At 2:00 I pinged")
    return re.findall(__________, text)

Use Ok to test your code:

python3 ok -q match_time

Q5: Most Common Area Code

Write a function which takes in a body of text and finds the most common area code. Area codes must be part of a valid phone number.

To solve this problem, we will first write a regular expression which finds valid phone numbers and captures the area code. See the docstring of area_codes for specifics on what qualifies as a valid phone number.

import re

def area_codes(text):
    Finds all phone numbers in text and captures the area code. Phone numbers
    have 10 digits total and may have parentheses around the area code, and
    hyphens or spaces after the third and sixth digits.

    >>> area_codes('(111) 111 1111, 1234567890 and 123 345 6789 should be matched.')
    ['111', '123', '123']
    >>> area_codes("1234567890 should, but 54321 and 654 456 78901 should not match")
    >>> area_codes("no matches for 12 3456 7890 or 09876-54321")
    return re.findall(__________, text)

Use Ok to test your code:

python3 ok -q area_codes

Now that we can get an area code, we just need to find the most common area code from a list. You may find the list.count method useful.

def most_common_code(text):
    Takes in an input string which contains at least one phone number (and
    may contain more) and returns the most common area code among all phone
    numbers in the input. If there are multiple area codes with the same
    frequency, return the first one that appears in the input text.

    >>> most_common_code('(501) 333 3333')
    >>> input_text = '''
    ... (123) 000 1234 and 12454, 098-123-0941, 123 451 0951 and 410-501-3021 has
    ... some phone numbers. '''
    >>> most_common_code(input_text)
    "*** YOUR CODE HERE ***"

Use Ok to test your code:

python3 ok -q most_common_code