More handy tools

INPUT · Slides

Replace by pattern

01 / 07

What replace cannot do

In Chapter 2 you met replace. Write text.replace("020", "0161") and one fixed piece of text becomes another.

But what about "turn every digit into a *"? Digits run from 0 to 9, and how many of them there are varies. Ten calls to replace? Even then you could not treat a run of them as one.

What you want is to replace by shape. That is what re.sub is for.

text = "phone 020-7946-0123"print(text.replace("020", "0161"))

Result

phone 0161-7946-0123

02 / 07

The shape of re.sub

You hand over three things: re.sub(shape, what to put instead, the original text). The order is what, with what, and where.

Every place that fits gets replaced. As with replace, the original text is left alone — a new string comes back.

import reprint(re.sub(r"\d", "*", "phone 020-7946"))

Result

phone ***-****

03 / 07

Replace a whole run at once

Change \d to \d+ and a run of digits is replaced as one. However many digits there are, you get a single symbol.

With \d you get one * per digit, which gives away how many there were. Choosing how much counts as one is the interesting part of re.sub.

import reprint(re.sub(r"\d+", "#", "apples 3kg oranges 12kg"))

Result

apples #kg oranges #kg

04 / 07

Use what you took out on the other side

What you wrapped in ( ) is available on the replacement side as \1, \2. Same numbers as the group(1) and group(2) of last lesson.

Do not forget the r on the replacement string as well. You want the backslash passed through exactly as typed on that side too.

import reprint(re.sub(r"(\d+)-(\d+)", r"\2-\1", "020-7946"))

Result

7946-020

05 / 07

Split by shape with re.split

The split in Chapter 2 could only take one separator. A string like "a,b c", with commas and spaces mixed, defeats it.

re.split lets you write the separator as a shape. Put [, ] and you have "either a comma or a space".

import reprint("a,b c".split(","))print(re.split(r"[, ]", "a,b c"))

Result

['a', 'b c']
['a', 'b', 'c']

06 / 07

Separators in a row are fine too

Two separators next to each other and re.split leaves an empty string in between. Split "apples; oranges,grapes" on [;, ] and one empty item slips in.

+ is what stops that. Write [;, ]+ and "one or more separators in a row" counts as a single separator. When in doubt, add the +.

import reprint(re.split(r"[;, ]", "apples; oranges,grapes"))print(re.split(r"[;, ]+", "apples; oranges,grapes"))

Result

['apples', '', 'oranges', 'grapes']
['apples', 'oranges', 'grapes']

07 / 07

What this group came to

Here is what regular expressions can do for you.

  • re.search — is that shape in there? None if it is not
  • re.findall — collect every place that fits
  • re.sub — replace by shape
  • re.split — split by shape

What they share is that you say shape rather than fixed text.

You do not need every symbol. Read \d, + and ( ) and you can read most of the code you will meet. Look the rest up when the day comes.