Week 7: Strings

Week 7: In-Class#

Demo#

Demo 7.1: Most Vowels#

Each word in a sentence might contain several vowels. We would like to find the word with the highest vowel count in a sentence.

Here, vowels are aeiou in either upper or lower case. If multiple words have the same highest number of vowels, we are interested in the first one. You can assume that at least one word contains a vowel.

Pen & Paper

Come up with two sentences to test a function solving this problem. The sentences should cover different cases. For each sentence, write down which word should be returned, and which case the sentence covers.

If you do not have a pen or paper at hand, you can type your answers here:

SentenceReturned wordCase covered

Demo 7.2: Standardize Address#

We need to combine addresses from multiple sources, which write the postal code and city name in different ways. The differences are:

  • Some write the postal code first (e.g. 2840 Holte), while others write the city first (e.g. Holte 2840).

  • Some use spaces to separate the words (as above), while others use underscores (e.g. 2840_Holte).

We want to standardize the addresses such that the postal code always comes first, and a space is always used for separating the parts of the address. The city name may consist of multiple words, but you may assume that it only consists of letters and word separators (space or underscore). The postal code can have any length, but it consists only of digits.

Pen & Paper

Come up with four addresses to test a function solving this problem. The addresses should together cover different cases. For each address, write down which case it covers.

If you do not have a pen or paper at hand, you can type your answers here:

AddressCase covered

Coding Practice#

Code 7.3: Framed Sign#

Define a variable and assign it a string value which is not longer than a line, for example This is my important message!. Write Python code to print the message between two border lines as shown below. Your code should work for any string value assigned to the variable.

-----------------------------
This is my important message!
-----------------------------

Modify your code such that it also prints the vertical bars on the left and right side of the message as shown below.

---------------------------------
| This is my important message! |
---------------------------------

Make another modification to your code where you define a variable to store a character, for example *. This character will be used for the horizontal borders, such that the code now prints the message below.

*********************************
| This is my important message! |
*********************************

Code 7.4: Framed Sign Function#

Based on the previous code, write a function print_framed_sign(message, border_char) that takes two arguments, a message and a character to be used for the border. The function should print the message between two border lines as shown below. Your function should work for any string value assigned to the variable.

Test your function with several different messages.

Add yet another argument to the function, is_important, which is a boolean value. If is_important is True, the function should print the message in uppercase letters. If is_important is False, the function should print the message as it is.

Now, your function should work as shown below.

>>> print_framed_sign("Harry, did you put your name in the goblet of fire?", "~", True)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| HARRY, DID YOU PUT YOUR NAME IN THE GOBLET OF FIRE? |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Lastly, apart from having a function which prints the framed message, we also want to have a function which returns a string instead of printing it. Make another function framed_sign(message, border_char, is_important) which returns the framed message instead of printing it. Start by copying the code from the previous function and modify it to return the framed message instead of printing it. The returned string value should contain the framed message in three lines of text.

Test your function with several different messages. Make sure that the framed_sign() function does not print anything when called. It should work as shown below.

>>> sign = framed_sign("Harry, did you put your name in the goblet of fire?", "X", True)
>>> print(sign)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| HARRY, DID YOU PUT YOUR NAME IN THE GOBLET OF FIRE? |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Code 7.5: Count Vowels#

Define a variable and assign it a string value, for example Hello, what a beautiful day!. Write Python code to traverse the string, and print every character in the string.

Now change your code so that it for every character prints whether this character is a vowel or not. We consider the vowels to be a, e, i, o, and u.

Modify your code such that it also counts the number of vowels in the string and prints the total number of vowels at the end.

Code 7.6: Count Vowels Function#

Based on the previous code, write a function vowel_count(message) that takes a message as an argument and returns the number of vowels in the message. This function should not print anything, only return the number of vowels. It should work as shown below.

>>> vowel_count("Hello, what's up?")
4
>>> vowel_count("OMG, I can't believe it!")
8
>>> vowel_count("This is a day when I'm feeling good")
11

Code 7.7: Format Dates#

Define a string variable with your birth date formatted as dd/mm/yyyy for example 13/01/1982. Write Python code to split the string into three strings, the day, the month, and the year. Now define a string variable with the date formatted as yyyy-mm-dd.

Now we want to format the date as dd-Mon-yy, for example 13-Jan-82. To accomplish this make a list of strings with the 3-letter abbreviation for each month. You need to appropriately manipulate the month part of the date to get the abbreviation.

Code 7.8: Format Dates Function#

Based on the previous code, write a function format_date(date) that takes a date string in dd/mm/yyyy format, and returns the date in dd-Mon-yy format. The function should work as shown below.

>>> format_date("01/08/2020")
'01-Aug-20'

Problem Solving#

Problem 7.9: DNA Complement#

A strand of DNA may be represented as text consisting of letters A, T, C, and G. The complement of a DNA string is formed by replacing each nucleotide with its complement: A with T, T with A, C with G, and G with C. For example, the complement of AATTCG is TTAAGC. The reverse complement of a DNA string is the complement of the string read in reverse. For example, the reverse complement of AATTCG is CGAATT.

Write a function dna_complement which takes two inputs: a string dna representing a DNA strand, and a boolean reverse. The function should return the complement of the DNA strand. If reverse is True, the function should return the reverse complement.

Problem 7.10: Change Case#

Two naming conventions for multi-word variable names are snake case and camel case. Snake case uses underscores instead of spaces. Camel case separates words with a single capitalized letter (here, the first letter is lowercase). An example of snake case is circle_radius, and the corresponding camel case is circleRadius. Single-word variable names are the same in both conventions.

Create a function that takes as input a string with the variable name in either snake case or camel case, and returns a string with the variable name in the other case. The variable name may be a single word or a multi-word name.

For example, consider the variable name thisIsAnIdentifierName. The presence of capital letters indicates that this is camel case. The individual words are: this is an identifier name. Written using snake case, this would be this_is_an_identifier_name.

change_case.py

change_case(name)

Changes camel case to snake case and vice versa.

Parameters:

  • name

str

A variable name in either camel case or snake case.

Returns:

  • str

The variable name in the other case.

You can test your function with the following inputs.

Hide tests

tests = []
tests.append(change_case('thisIsIdentifierName') == 'this_is_identifier_name')
tests.append(change_case('this_is_an_identifier_name') == 'thisIsAnIdentifierName')
tests.append(change_case('justChecking') == 'just_checking')
tests.append(change_case('just_checking') == 'justChecking')
tests.append(change_case('one_two_three_words') == 'oneTwoThreeWords')
tests.append(change_case('oneTwoThreeWords') == 'one_two_three_words')
tests.append(change_case('singleword') == 'singleword')
tests.append(change_case('this_is_a_valid_name') == 'thisIsAValidName')
tests.append(change_case('thisIsAlsoValidName') == 'this_is_also_valid_name')
tests.append(change_case('nowWhat') == 'now_what')
tests.append(change_case('we_are_done') == 'weAreDone')

print("All tests passed:", all(tests))

Problem 7.11: Generalized Palindrome#

A palindrome is a word that reads the same forwards and backwards. For example, racecar is a palindrome. A sentence or phrase can also be a palindrome, where punctuation and spaces are ignored. For example, A man, a plan, a canal: Panama! is a palindrome, and so is Was it a car or a cat I saw?.

Write a function is_palindrome that takes as input a string containing a word or a sentence. The function should return True if the string is a palindrome and False otherwise. The function should ignore punctuation, spaces, and capitalization. You can consider punctuation to be any of the following characters: ,.?!:;.

Test your function on the following inputs.

Hide tests

tests = []
tests.append(is_palindrome('racecar'))
tests.append(is_palindrome('A man, a plan, a canal: Panama!'))
tests.append(is_palindrome('Was it a car or a cat I saw?'))
tests.append(is_palindrome('Damejer nis berg greb sin rejemad.'))
tests.append(is_palindrome('A Santa at NASA.'))
tests.append(not is_palindrome('Morten'))
tests.append(not is_palindrome('Not a palindrome'))
tests.append(is_palindrome('Madam'))
tests.append(not is_palindrome('Palindromes are cool'))
tests.append(not is_palindrome('Level and level'))
tests.append(not is_palindrome('Sequence of letters.'))

print("All tests passed:", all(tests))

Problem 7.12: Punctuation Check#

In typed text, some punctuation marks should always be followed by a space. These include:

  • Punctuation used for ending a sentence: period (.), question mark (?), and exclamation mark (!).

  • Punctuation indicating a pause: comma (,), colon (:), and semicolon (;).

For an automatic text evaluation, we need to count the number of punctuation errors, where punctuation marks (.), (?), (!), (,), (:), and (;) are not followed by a space. If the last character in the text is a punctuation mark, it should not be counted as an error.

Write a function punctuation_check that takes as input a string representing a typed text and returns the number of punctuation errors.

Consider the string 'This is:a text, a text with many,many errors! But,who cares?' which has the following punctuation errors: :a, ,m, and ,w. So the function should return 3 for this string.

The function should have the following specifications:

punctuation_check.py

punctuation_check(text)

Counts the number of punctuation marks that are not followed by a space.

Parameters:

  • text

str

Input text to check.

Returns:

  • int

Number of punctuation marks not followed by a space.

Try to run the following code to test your function on ten different strings. The expected output is: 3, 2, 1, 0, 0, 2, 1, 8, 0, 5.

print(punctuation_check("This is:a text, a text with many,many errors! But,who cares?"))
print(punctuation_check("Here we have no errors.Or do we?!"))
print(punctuation_check("No,I am sure this is error-free!"))
print(punctuation_check("Whataboutonlyasingleword? "))
print(punctuation_check("       almost   empty    ?     "))
print(punctuation_check("3 times.is.not enough"))
print(punctuation_check("!Whou, this is strange!"))
print(punctuation_check("A,B,C,D,E,F,G,H,I"))
print(punctuation_check("Number nine is a good example, almost no problems there-I think."))
print(punctuation_check("But!The last text is bad.Really,really bad.No space at all.Squeezed!"))

Problem 7.13: Code Shift#

A bike lock has 4 dials each with the digits from 0 to 9. The code is set by turning the dials in discrete steps. Turning a dial for one step will increment the digits from 0 to 9, but digit 9 will be set to 0. The dials can be turned in both directions, and we define the positive direction as the direction where digits smaller than 9 increase. If all dials of the lock are turned at once, all code digits will change.

Write a function code_shift which as an input takes a string representing the 4-digit code, and an integer representing a turn of all dials for a number of steps in a positive or a negative direction. The function should return the string with the new code after the turn.

For example, consider the code '2638' and the shift 3. The code consists of digits 2, 6, 3, and 8. Turning the dials for three steps in a positive direction will change the first digit into 2+3=5, the second digit will become 9, the third digit will become 6. The last digit will become 1, as it changes from 8 over 9 and 0 to 1. So the function should return '5961'.

The function should have the following specifications:

code_shift.py

code_shift(code, turn)

Shifts the code by a given number of steps.

Parameters:

  • code

str

A 4-digit code.

  • turn

int

A number of steps to turn all lock dials.

Returns:

  • str

The code after turning all lock dials.

You can test your function with the following inputs.

Hide tests

tests = []
tests.append(code_shift('2638', 3) == '5961')
tests.append(code_shift('0120', -3) == '7897')
tests.append(code_shift('9165', 1) == '0276')

print("All tests passed:", all(tests))

Solutions to Demo Tasks