Today: more string algorithms, str in, if/else, quick-return, str.find(), slices

More detailed guides: Python-String, Python-If

Problems today:

> str2 functions

Patterns Foreach Accumulate

Loop over string, adding to result as we go.

String Functions

>>> 'a'.isalpha()
True
>>> '5'.isdigit()
True
>>> 'H'.isupper()
True
>>> 'H'.islower()
False
>>> 'H'.lower()
'h'
>>> 'H'.isalpha()
True
>>> 'a'.upper()
'A'
>>> '5'.isalpha()
False
>>> '5'.upper()  # other chars unchanged
'5'

alpha_up()

'12abc34' -> 'ABC'

Given string s. Return a string made of all the alphabetic chars in s, converted to uppercase form.

Use string functions .isalpha() and .upper()

Solution

def alpha_up(s):
    result = ''
    for i in range(len(s)):
        if s[i].isalpha():
            result += s[i].upper()
    return result

if Variation: if / else

if test:
  Lines-A
else:
  Lines-B

str_dx()

'12abc34' -> 'ddxxxdd'

Solution code

def str_dx(s):
    result = ''
    for i in range(len(s)):
        if s[i].isdigit():
            result += 'd'
        else:
            result += 'x'
    return result

catty()

'xCtxxxAax' -> 'CtAa'

Return a string made of the chars from the original string, whenever the chars are 'c' 'a' or 't', (either lower or upper case). So the string 'xaCxxxTx' returns 'aCT'.

Idea: Decomp By Var

Solution

def catty(s):
    result = ''
    for i in range(len(s)):
        # Create "low" var of intermediate result
        low = s[i].lower()
        if low == 'c' or low == 'a' or low == 't':
            result += s[i]  # Use original, not low
    return result
    # Cute non-obvious alternative: use "in"
    # to do the "or" logic for us, like this:
    # if low in 'cat':

Without Decomp-by-var

if s[i].lower() == 'c' or s[i].lower() == 'a' or s[i].lower() == 't':

With Decomp-by-var - better

low = s[i].lower()
if low == 'c' or low == 'a' or low == 't':

String in Test

>>> 'c' in 'abcd'
True
>>> 'bc' in 'abcd'
True
>>> 'bx' in 'abcd'
False
>>> 'A' in 'abcd'
False

Pattern: Quick Return

first_alpha()

'123abc' -> 'a'

Given a string s, return the first alphabetic char in s, or None if there is no alphabetic char. Demonstrates quick-return strategy.

Solution

def first_alpha(s):
    for i in range(len(s)):
        if s[i].isalpha():
            return s[i]
            # 1. Exit immediately if found
    # 2. If we get here,
    # there was no alpha char.
    return None

has_digit()

Use quick-return strategy, returning True or False.

Given a string s, return True if there is a digit in the string somewhere, False otherwise.

Solution - same pattern as first_alpha(), but returns boolean instead of a char

    for i in range(len(s)):
        if s[i].isdigit():
            # 1. Exit immediately if found
            return True
    # 2. If we get here,
    # there was no digit.
    return False

String find()

alt:string 'Python' shown with index numbers 0..5

>>> s = 'Python'
>>> s.find('t')
2
>>> s.find('th')
2
>>> s.find('n')
5
>>> s.find('N')
-1
>>> s.find('x')
-1

Python String Slices

>>> s = 'Python'
>>> s[1:3]
'yt'
>>> s[1:5]
'ytho'
>>> s[1:1]    # "not including" dominates
''
>>>
>>> s[:3]     # omit = from/to end
'Pyt'
>>> s[4:]
'on'
>>> s[4:999]  # too big = to end
'on'
>>> s[:4]     # "perfect split" on 4
'Pyth'
>>> s[4:]
'on'
>>> s[:]      # the whole thing
'Python'

brackets()

A first venture into using index numbers and slices. Many, many problems work in this domain - e.g. extracting all the hashtags from your text messages.

'cat[dog]bird' -> 'dog'

> brackets

Brackets Observations

Solution

def brackets(s):
    left = s.find('[')
    if left == -1:
        return ''
    right = s.find(']')
    # Use slice to pull out chars between left/right
    # make a drawing!
    return s[left + 1: right]

Optional: Negative Slice

>>> s = 'Python'
>>> s[len(s)-1]
'n'
>>> s[-1]
'n'
>>> s[-2]
'o'
>>> s[1:-3]
'yt'
>>> s[-3:]
'hon'