More handy tools

INPUT · Slides

Search by shape

01 / 07

Looking for something you cannot put into words

In Chapter 2 you met in and find. Both answer the same sort of question: is this word in there?

But what you are after cannot always be put into words.

  • the place where the digits run together
  • the bit that looks like a postcode
  • a run of lowercase letters

None of those is a word. Each one is a shape. The notation for writing a shape down is called a regular expression.

02 / 07

Import re, then search

Regular expressions live in a module called re. Bring it in with the import from Chapter 6.

The one you will reach for most is re.search. It looks for the shape anywhere in the text and hands back the part it found.

r"\d+" is the shape. \d is one digit and + is one or more, so together they mean "a run of one or more digits".

import retext = "the phone number is 02079460123"m = re.search(r"\d+", text)if m:    print(m.group())

Result

02079460123

03 / 07

Why the r goes in front

When you write a shape, put an r in front of the quotes. It stands for raw.

In an ordinary string \n turns into a single newline character — the backslash gets eaten as a signal.

An r switches that reading off and passes the two characters you actually typed. Regular expressions are full of backslashes, so treat the r as compulsory.

print(r"\n")print(len(r"\n"))print(len("\n"))

Result

\n
2
1

04 / 07

These are all the symbols you need

There are a great many symbols in regular expressions. This chapter uses only the nine below.

SymbolMeaning
\done digit
\wone word character (letter, digit or underscore)
.any one character
+one or more of what came before
*zero or more of what came before
{3}exactly three of what came before
[a-z]any one character in that range
^the start
$the end

You do not have to memorise them. Knowing such things exist, and being able to look them up when the moment comes, is plenty.

import reprint(re.findall(r"\d+", "apples 3kg oranges 12kg"))print(re.findall(r"[a-z]+", "apples 3kg"))

Result

['3', '12']
['apples', 'kg']

05 / 07

Nothing found means None

This is the important one. re.search returns None when it finds nothing.

There is no error. None simply comes back, quietly. What you learned in Chapter 1 about there being no value starts to earn its keep here.

import rem = re.search(r"\d+", "no numbers here")print(m)

Result

None

06 / 07

Check before you call group

None has no group(). Call it without checking and the program falls over.

So whenever you use a regular expression, wrap it in if m:. This is the set phrase.

m = re.search(r"\d+", text)if m:    print(m.group())

Write those three lines until your fingers know them. They are the basic manners for handling something that might not be there.

import rem = re.search(r"\d+", "no numbers here")print(m.group())

Result

AttributeError: 'NoneType' object has no attribute 'group'

07 / 07

findall for all of them, match from the start

re.search has two relatives.

  • re.findall — collects every place that fits and returns them as a list of strings. Nothing found gives an empty list
  • re.match — only asks whether the text fits from the very start. One in the middle it will not find

findall gives you a list, so there is no group() to call. Of the three it is the easiest to reach for.

Next lesson you will learn how to break a match up further.

import reprint(re.findall(r"\d+", "a1b22"))m = re.match(r"\d+", "123abc")if m:    print(m.group())print(re.match(r"\d+", "abc123"))

Result

['1', '22']
123
None