\chapter{Strings part 2}

\section{\pythoninline{str} Methods}
\label{sec-string-module}
The \pythoninline{str} type contains useful methods that manipulate
strings. 
To see what methods are available, use the \pythoninline{dir} function
with \pythoninline{str} as an argument.

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> dir(str)
\end{pythonInteractive}
\end{minipage}
which will return the list of items inside the string module: 

\begin{minipage}{\textwidth}
\begin{pythonOutput}
  ['__add__', '__class__', '__contains__', '__delattr__', '__doc__',
  '__eq__', '__ge__', '__getattribute__', '__getitem__',
  '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__',
  '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__',
  '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__',
  '__rmul__', '__setattr__', '__str__', 'capitalize', 'center',
  'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find',
  'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace',
  'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip',
  'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition',
  'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
  'swapcase', 'title', 'translate', 'upper', 'zfill']
\end{pythonOutput}
\end{minipage}
To find out more about an item in this list, we can use the
\pythoninline{help} 
command:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> help(str.capitalize)
Help on method_descriptor:

capitalize(...)
    S.capitalize() -> string
    
    Return a copy of the string S with only its first character
    capitalized.
\end{pythonInteractive}
\end{minipage}
We can call any of these methods using \myidx{dot~notation}:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> s = "brendan"
>>> s.capitalize()
'Brendan'
\end{pythonInteractive}
\end{minipage}

\pythoninline{str.find} is a method which does much the same thing as the
function we wrote in the last lecture. To find out more about it, we
can print out its 
\myidx{docstring}, \pythoninline{\_\_doc\_\_}, which contains
documentation on the function:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> print str.find.__doc__
S.find(sub [,start [,end]]) -> int

Return the lowest index in S where substring sub is found,
such that sub is contained within s[start,end].  Optional
arguments start and end are interpreted as in slice notation.

Return -1 on failure.
\end{pythonInteractive}
\end{minipage}
Calling the \pythoninline{help} function also prints out the
docstring:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> help(str.find)
Help on method_descriptor:

find(...)
    S.find(sub [,start [,end]]) -> int
    
    Return the lowest index in S where substring sub is found,
    such that sub is contained within s[start,end].  Optional
    arguments start and end are interpreted as in slice notation.
    
    Return -1 on failure.
\end{pythonInteractive}
\end{minipage}
The parameters in square brackets are optional parameters. We can use
\pythoninline{str.find} much as we did our own find:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> fruit = "banana"
>>> index = fruit.find("a")
>>> print index
1
\end{pythonInteractive}
\end{minipage}
This example demonstrates one of the benefits of modules---they help
avoid collisions between the names of built-in functions and
user-defined functions. By using dot notation we can specify which
version of \pythoninline{find} we want.
Actually, \pythoninline{str.find} is more general than our version.
It can find substrings, not just characters:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> fruit.find("na")
2
\end{pythonInteractive}
\end{minipage}
Like ours, it takes an additional argument that specifies the index
at which it should start:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> fruit.find("na", 3)
4
\end{pythonInteractive}
\end{minipage}
Unlike ours, its second optional parameter specifies the index at
which the search should end:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> "bob".find("b", 1, 2)
-1
\end{pythonInteractive}
\end{minipage}
In this example, the search fails because the letter \emph{b} does
not appear in the index range from 1 to 2 (not including 2).

\section{Character classification}

It is often helpful to examine a character or string and test whether it is
upper- or lowercase, or whether it is a character or a digit. The
\pythoninline{str} type includes several methods for this
functionality:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> "3".isalnum()       % alphabetical or numeral
True
>>> "3".isalpha()        % alphabetical
False
>>> "hello".isalpha()
True
>>> "342".isdigit()     % numeral
True
>>> "hello".islower()  % lower case
True
>>> "hello".isupper() % upper case
False
>>> " ".isspace()        % whitespace
True
>>> "Hello".istitle()    % capitalised
True
>>> "hello".istitle()
False
>>> 
\end{pythonInteractive}
\end{minipage}

\section{String formatting}
The most concise and powerful way to format a string in Python is to
use the \emph{string formatting operator}, \pythoninline{\%}, together with
Python's string formatting operations. To see how this works, let's
start with a few examples:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> "His name is %s."  % "Arthur"
'His name is Arthur.'
>>> name = "Alice"
>>> age = 10
>>> "I am %s and I am %d years old." % (name, age)
'I am Alice and I am 10 years old.'
>>> n1 = 4
>>> n2 = 5
>>> "2**10 = %d and %d * %d = %f" % (2**10, n1, n2, n1*n2)
'2**10 = 1024 and 4 * 5 = 20.000000'
>>>
\end{pythonInteractive}
\end{minipage}
The syntax for the string formatting operation looks like this:

\begin{minipage}{\textwidth}
\begin{python}
"<FORMAT>" % (<VALUES>)
\end{python}
\end{minipage}
It begins with a \myidx{format} which contains a sequence of
characters and \myidx{conversion specifications}. Conversion
specifications start with a \pythoninline{\%} operator. Following the
format string is a single \pythoninline{\%} and then a sequence of
values, \emph{one per conversion specification}, separated by commas
and enclosed in parentheses. The parentheses are optional if there is
only a single value. 

In the first example above, there is a single conversion
specification, \pythoninline{\%s}, which indicates a string. The
single value, ``Arthur'', maps to it, and is not enclosed in
parentheses.
In the second example, \pythoninline{name} has string value,
``Alice'', and \pythoninline{age} has
integer value, 10. These map to the two conversion specifications,
\pythoninline{\%s} and \pythoninline{\%d}. The \pythoninline{d} in the
second conversion specification indicates that the value is a decimal
integer.
In the third example variables \pythoninline{n1} and \pythoninline{n2}
have integer values \pythoninline{4} and \pythoninline{5}
respectively. There are four conversion specifications in the format
string: three \pythoninline{\%d}'s and a \pythoninline{\%f}. The
\pythoninline{f} indicates that the value should be represented as a
floating point number. The four values that map to the four
conversion specifications are: \pythoninline{2**10},
\pythoninline{n1}, \pythoninline{n2}, and \pythoninline{n1*n2}. 

\pythoninline{s}, \pythoninline{d}, and \pythoninline{f} are all the
conversion types we will need for this 
book. To see a complete list, see the String Formatting Operations
section of the Python Library Reference.
The following example illustrates the real utility of string
formatting:

\begin{minipage}{\textwidth}
\begin{python}
i = 1
print "i\ti**2\ti**3\ti**5\ti**10\ti**20"
while i <= 10:
    print i, '\t', i**2, '\t', i**3, '\t', i**5, '\t', i**10, '\t', i**20
    i += 1
\end{python}
\end{minipage}
This program prints out a table of various powers of the numbers from
1 to 10. In its current form it relies on the tab character
($\backslash$t) to align the columns of values, but this breaks down
when the values in the table get larger than the 8 character tab
width:

\begin{minipage}{\textwidth}
\begin{pythonOutput}
i       i**2    i**3    i**5    i**10   i**20
1       1       1       1       1       1
2       4       8       32      1024    1048576
3       9       27      243     59049   3486784401
4       16      64      1024    1048576         1099511627776
5       25      125     3125    9765625         95367431640625
6       36      216     7776    60466176        3656158440062976
7       49      343     16807   282475249       79792266297612001
8       64      512     32768   1073741824      1152921504606846976
9       81      729     59049   3486784401      12157665459056928801
10      100     1000    100000  10000000000     100000000000000000000
\end{pythonOutput}
\end{minipage}
One possible solution would be to change the tab width, but the first
column already has more space than it needs. The best solution would
be to set the width of each column independently. As you may have
guessed by now, string formatting provides the solution:

\begin{minipage}{\textwidth}
\begin{python}
i = 1
print "%-4s%-5s%-6s%-8s%-13s%-15s" %
      ('i', 'i**2', 'i**3', 'i**5', 'i**10', 'i**20')
while i <= 10:
    print "%-4d%-5d%-6d%-8d%-13d%-15d" % (i, i**2, i**3, i**5, i**10, i**20)
    i += 1
\end{python}
\end{minipage}
Running this version produces the following output:

\begin{minipage}{\textwidth}
\begin{pythonOutput}
i   i**2 i**3  i**5    i**10        i**20          
1   1    1     1       1            1              
2   4    8     32      1024         1048576        
3   9    27    243     59049        3486784401     
4   16   64    1024    1048576      1099511627776  
5   25   125   3125    9765625      95367431640625 
6   36   216   7776    60466176     3656158440062976
7   49   343   16807   282475249    79792266297612001
8   64   512   32768   1073741824   1152921504606846976
9   81   729   59049   3486784401   12157665459056928801
10  100  1000  100000  10000000000  100000000000000000000
\end{pythonOutput}
\end{minipage}
The \pythoninline{-} after each \pythoninline{\%} in the conversion
specifications indicates left 
justification. The numerical values specify the minimum length, so
\pythoninline{\%-13d} is a left justified number at least 13
characters wide. 

\section{Glossary}
\begin{description}
\item[dot notation]Use of the \myidx{dot operator}, ., to access
   functions inside a module.
\item[docstring]A string constant on the first line of a function or
   module definition (and as we will see later, in class and method
   definitions as well). Docstrings provide a convenient way to
   associate documentation with code. Docstrings are also used by the
   doctest module for automated testing.
\item[whitespace:]Any of the characters that move the cursor without
   printing visible characters. The constant string.whitespace
   contains all the white-space characters.
\end{description}

\newpage
\section{Laboratory exercises}

\begin{enumerate}

\item Try each of the following formatted string operations in a
Python shell and record the results: 
\begin{enumerate}
   \item ``\%s \%d \%f'' \% (5, 5, 5)
\begin{answerspace}
zend
\end{answerspace}
   \item ``\%-.2f'' \% 3
\begin{answerspace}
zend
\end{answerspace}
   \item ``\%-10.2f\%-10.2f'' \% (7, 1.0/2)
\begin{answerspace}
zend
\end{answerspace}
   \item print `` \$\%5.2f$\backslash$n \$\%5.2f$\backslash$n
     \$\%5.2f'' \% (3, 4.5, 11.2)
\begin{answerspace}
zend
\end{answerspace}
\end{enumerate}
\item The following formatted strings have errors. Fix
them: \begin{enumerate}
   \item ``\%s \%s \%s \%s'' \% ('this', 'that', 'something')
\begin{answerspace}
zend
\end{answerspace}
   \item ``\%s \%s \%s'' \% ('yes', 'no', 'up', 'down')
\begin{answerspace}
zend
\end{answerspace}
   \item ``\%d \%f \%f'' \% (3, 3, 'three')
\begin{answerspace}
zend
\end{answerspace}
   \end{enumerate}

\item Add the following functions to the file \pythoninline{stringtools.py}.

\begin{minipage}{\textwidth}
\begin{python}
def count(sub, s):
    """
      >>> count('is', 'Mississippi')
      2
      >>> count('an', 'banana')
      2
      >>> count('ana', 'banana')
      2
      >>> count('nana', 'banana')
      1
      >>> count('nanan', 'banana')
      0
    """

def remove(sub, s):
    """
      >>> remove('an', 'banana')
      'bana'
      >>> remove('cyc', 'bicycle')
      'bile'
      >>> remove('iss', 'Mississippi')
      'Missippi'
      >>> remove('egg', 'bicycle')
      'bicycle'
    """

def remove_all(sub, s):
    """
      >>> remove_all('an', 'banana')
      'ba'
      >>> remove_all('cyc', 'bicycle')
      'bile'
      >>> remove_all('iss', 'Mississippi')
      'Mippi'
      >>> remove_all('eggs', 'bicycle')
      'bicycle'
    """

def is_palindrome(s):
    """
      >>> is_palindrome('abba')
      True
      >>> is_palindrome('abab')
      False
      >>> is_palindrome('tenet')
      True
      >>> is_palindrome('banana')
      False
      >>> is_palindrome('straw warts')
      True
    """
\end{python}
\end{minipage}
Add bodies to each of the functions, one at a time until all the doctests pass.
\end{enumerate}

