Nearby lessons

131 of 159

Python - Regex sub and subn

📌 What You Will Learn
  • Understand what substitution means in regular expressions
  • Use re.sub() to replace matched patterns and return the modified string
  • Understand how subn() returns a tuple with the replacement count
  • Limit the number of replacements using the count parameter
  • Compare sub() and subn() to choose the right function

Introduction to Substitution

Python's re module provides functions to replace matched Regular Expression patterns with another string.

The two important substitution functions are:

sub()
subn()
        

Both functions perform replacement, but their return values are different.

sub()
   │
   └── Returns the modified string

subn()
   │
   └── Returns a tuple
       (modified string, number of replacements)
        

Simple Definition:

Substitution means replacing the text matched by a Regular Expression with another text.

Suppose we have the following string:

a7b9c5kz
        

We want to replace every digit with:

#
        

The Regular Expression:

[0-9]
        

matches:

7
9
5
        

After replacement:

a#b#c#kz
        

This process is called substitution.

1. The sub() Function

The sub() function replaces every occurrence of the given Regular Expression pattern with the specified replacement string.

Simple Definition:

sub() replaces matched occurrences with another string and returns the resulting string.

Syntax:

re.sub(regex, replacement, target_string)
        

We can also write:

re.sub(pattern, repl, string)
        

Understanding sub() Syntax

re.sub(regex, replacement, target_string)
       │         │             │
       │         │             └── String to search
       │         │
       │         └── New replacement value
       │
       └── Regular Expression pattern
        

Example:

re.sub("[0-9]", "#", "a7b9c5kz")
        

Here:

Argument Value Purpose
Regex [0-9] Find digits
Replacement # Replace every matched digit with #
Target a7b9c5kz String in which replacement is performed

sub() Demo Program

Consider the statement:

s = re.sub("[0-9]", "#", "a7b9c5kz")
        

The target string is:

a7b9c5kz
        

The pattern:

[0-9]
        

matches every digit.

Python searches the target from left to right.

a → No Match → Keep a

7 → Match → Replace with #

b → No Match → Keep b

9 → Match → Replace with #

c → No Match → Keep c

5 → Match → Replace with #

k → No Match → Keep k

z → No Match → Keep z
        

Therefore:

Original : a7b9c5kz
Result   : a#b#c#kz
        

Replacement Diagram:

Original String

a 7 b 9 c 5 k z
  │   │   │
  ▼   ▼   ▼
  #   #   #

Result

a # b # c # k z
        

Only the characters matched by the Regular Expression are replaced.

All non-matching characters remain unchanged.

🐍Code Cell
1import re
2 
3s = re.sub("[0-9]", "#", "a7b9c5kz")
4 
5print(s)
Output
a#b#c#kz

sub() with \d

For this basic ASCII example:

[0-9]
        

and:

\d
        

both match the digits:

7
9
5
        

Therefore, both examples produce:

a#b#c#kz
        

Note: In Python 3, \d is Unicode-aware by default, so its behaviour is broader than [0-9] for some Unicode text.

🐍Code Cell
1import re
2 
3s = re.sub("\d", "#", "a7b9c5kz")
4 
5print(s)
Output
a#b#c#kz

sub() with Alphabet Replacement

The pattern:

[a-z]
        

matches every lowercase alphabet character.

The target:

a7b9c5kz
        

contains the lowercase letters:

a
b
c
k
z
        

Each one is replaced with #.

a → #
7 → 7
b → #
9 → 9
c → #
5 → 5
k → #
z → #
        

Therefore:

#7#9#5##
        
🐍Code Cell
1import re
2 
3s = re.sub("[a-z]", "#", "a7b9c5kz")
4 
5print(s)
Output
#7#9#5##

sub() When Pattern is Not Found

The target string:

abcdefgh
        

does not contain any digit.

Therefore:

[0-9]
        

does not match anything.

No replacement takes place, so the original content remains unchanged:

abcdefgh
        
🐍Code Cell
1import re
2 
3s = re.sub("[0-9]", "#", "abcdefgh")
4 
5print(s)
Output
abcdefgh

sub() Execution Flow

Program Starts
      │
      ▼
import re
      │
      ▼
Pattern = [0-9]
      │
      ▼
Replacement = "#"
      │
      ▼
Target =
"a7b9c5kz"
      │
      ▼
re.sub()
      │
      ▼
Search Target
from Left to Right
      │
      ▼
Pattern Matches?
      │
   ┌──┴──────────┐
   │             │
  Yes            No
   │             │
   ▼             ▼
Replace with    Keep Original
"#"             Character
   │             │
   └──────┬──────┘
          ▼
    Continue Search
          │
          ▼
     End of String
          │
          ▼
Return Modified String
          │
          ▼
    "a#b#c#kz"
          │
          ▼
        Print
          │
          ▼
         End
        

2. The subn() Function

The subn() function performs substitution just like sub().

But there is one important difference.

subn() also tells us how many replacements were performed.

Simple Definition:

subn() replaces matched occurrences and returns a tuple containing the modified string and the number of replacements.

Syntax:

re.subn(regex, replacement, target_string)
        

Return Value of subn()

The subn() function returns a tuple.

The general form is:

(modified_string, number_of_replacements)
        

For example:

('a#b#c#kz', 3)
        

Here:

'a#b#c#kz'
      │
      └── Modified String

3
│
└── Number of Replacements
        

A tuple returned by subn() contains exactly two items:

Position Value Meaning
0 Modified string Result after substitution
1 Replacement count Number of substitutions performed

Example:

t = ('a#b#c#kz', 3)

t[0] → 'a#b#c#kz'

t[1] → 3
        

subn() Demo Program

The important statement is:

t = re.subn("[0-9]", "#", "a7b9c5kz")
        

The pattern:

[0-9]
        

finds:

7
9
5
        

Each digit is replaced with:

#
        

The resulting string becomes:

a#b#c#kz
        

The total number of replacements is:

3
        

Therefore, subn() returns:

('a#b#c#kz', 3)
        
🐍Code Cell
1import re
2 
3t = re.subn("[0-9]", "#", "a7b9c5kz")
4 
5print(t)
Output
('a#b#c#kz', 3)

Accessing Values from the subn() Tuple

The returned tuple is:

('a#b#c#kz', 3)
        

The first element is available at index 0:

t[0]
        

which gives:

a#b#c#kz
        

The second element is available at index 1:

t[1]
        

which gives:

3
        

Because subn() returns two values inside a tuple, we can also unpack them directly:

result, count = re.subn("[0-9]", "#", "a7b9c5kz")

print("Result:", result)
print("Number of Replacements:", count)
        

Output:

Result: a#b#c#kz
Number of Replacements: 3
        

Conceptually:

('a#b#c#kz', 3)
       │       │
       ▼       ▼
    result   count
        

Therefore:

result = "a#b#c#kz"
count  = 3
        
🐍Code Cell
1import re
2 
3t = re.subn("[0-9]", "#", "a7b9c5kz")
4 
5print("Result:", t[0])
6print("Number of Replacements:", t[1])
Output
Result: a#b#c#kz
Number of Replacements: 3

subn() When No Match Exists

The target:

abcdefgh
        

does not contain any digit.

Therefore, no substitution is performed.

The resulting string remains:

abcdefgh
        

The replacement count is:

0
        

Hence:

('abcdefgh', 0)
        
🐍Code Cell
1import re
2 
3t = re.subn("[0-9]", "#", "abcdefgh")
4 
5print(t)
Output
('abcdefgh', 0)

subn() Execution Flow

Program Starts
      │
      ▼
import re
      │
      ▼
Pattern = [0-9]
      │
      ▼
Replacement = "#"
      │
      ▼
Target =
"a7b9c5kz"
      │
      ▼
re.subn()
      │
      ▼
Set Replacement
Count = 0
      │
      ▼
Search Target
from Left to Right
      │
      ▼
Pattern Matches?
      │
   ┌──┴─────────────┐
   │                │
  Yes               No
   │                │
   ▼                ▼
Replace with #     Keep Original
   │                │
   ▼                │
Increase Count      │
   │                │
   └────────┬───────┘
            ▼
       Continue
            │
            ▼
       End of String
            │
            ▼
Create Tuple
(modified string, count)
            │
            ▼
('a#b#c#kz', 3)
            │
            ▼
          Return
            │
            ▼
           End
        

sub() vs subn()

Both functions perform the same basic substitution operation.

The main difference is their return value.

                  Pattern Match
                       │
                       ▼
                    Replace
                       │
              ┌────────┴────────┐
              │                 │
              ▼                 ▼
            sub()             subn()
              │                 │
              ▼                 ▼
      Modified String      Modified String
                               +
                         Replacement Count
              │                 │
              ▼                 ▼
        "a#b#c#kz"      ("a#b#c#kz", 3)
        
Feature sub() subn()
Performs substitution Yes Yes
Uses Regular Expression Yes Yes
Replaces matching occurrences Yes Yes
Returns modified string Yes Inside tuple
Returns replacement count No Yes
Return type in these examples String Tuple
No matches Original string (original_string, 0)

Both functions use:

Pattern     = [0-9]
Replacement = #
Target      = a7b9c5kz
        

Both replace:

7 → #
9 → #
5 → #
        

So both produce the same modified text:

a#b#c#kz
        

But their returned values differ.

sub()  → a#b#c#kz

subn() → ('a#b#c#kz', 3)
        

The additional 3 tells us that three replacements were performed.

Complete Execution Flow:

                         Start
                           │
                           ▼
                        import re
                           │
                           ▼
                    Define Pattern
                           │
                           ▼
                  Define Replacement
                           │
                           ▼
                     Target String
                           │
               ┌───────────┴───────────┐
               │                       │
               ▼                       ▼
             sub()                   subn()
               │                       │
               ▼                       ▼
        Find Matching             Find Matching
        Occurrences               Occurrences
               │                       │
               ▼                       ▼
        Replace Matches           Replace Matches
               │                       │
               ▼                       ▼
        Modified String         Count Replacements
               │                       │
               │                       ▼
               │                  Create Tuple
               │                       │
               ▼                       ▼
          Return String       Return (String, Count)
               │                       │
               └───────────┬───────────┘
                           ▼
                         Output
                           │
                           ▼
                          End
        
🐍Code Cell
1import re
2 
3target = "a7b9c5kz"
4 
5result1 = re.sub("[0-9]", "#", target)
6result2 = re.subn("[0-9]", "#", target)
7 
8print("sub():", result1)
9print("subn():", result2)
Output
sub(): a#b#c#kz
subn(): ('a#b#c#kz', 3)

Limiting Replacements with count

Both sub() and subn() support an optional count argument.

Syntax:

re.sub(pattern, replacement, string, count)

re.subn(pattern, replacement, string, count)
        

The count value specifies the maximum number of replacements.

For example:

re.sub("[0-9]", "#", "a7b9c5", 2)
        

Only the first two digits are replaced.

In the program below, the target contains three digits:

7
9
5
        

But:

count = 2
        

Therefore, only the first two matches are replaced:

7 → #
9 → #
5 → remains unchanged
        

The result is:

a#b#c5kz
        

Default count behaviour: If the count argument is not specified, Python replaces all non-overlapping matches. For example:

re.sub("[0-9]", "#", "a7b9c5")
        

replaces all three digits.

We can also explicitly use count = 0 to mean no replacement limit:

re.sub("[0-9]", "#", "a7b9c5", 0)
        

Result:

a#b#c#
        
🐍Code Cell
1import re
2 
3s = re.sub("[0-9]", "#", "a7b9c5kz", 2)
4 
5print(s)
Output
a#b#c5kz

subn() with count

Only two substitutions are allowed.

Therefore:

Modified String = a#b#c5kz
Replacement Count = 2
        

The returned tuple is:

('a#b#c5kz', 2)
        
🐍Code Cell
1import re
2 
3t = re.subn("[0-9]", "#", "a7b9c5kz", 2)
4 
5print(t)
Output
('a#b#c5kz', 2)

Quick Revision and Important Notes

Quick Revision:

sub()
 │
 ├── Finds matches
 │
 ├── Replaces matches
 │
 └── Returns modified string


subn()
 │
 ├── Finds matches
 │
 ├── Replaces matches
 │
 ├── Counts replacements
 │
 └── Returns tuple
       │
       └── (modified_string, count)
        

Easy memory rule:

sub  → Substitute

subn → Substitute + Number
        

Summary:

  • Substitution means replacing text matched by a Regular Expression.
  • Python provides sub() and subn() for Regular Expression substitution.
  • sub() replaces matched occurrences with the specified replacement.
  • sub() returns the modified string.
  • The basic syntax is re.sub(pattern, replacement, target).
  • subn() performs the same substitution operation.
  • subn() additionally counts how many substitutions were performed.
  • subn() returns a tuple.
  • The tuple format is (modified_string, number_of_replacements).
  • For a7b9c5kz, replacing digits with # produces a#b#c#kz.
  • In that example, subn() returns ('a#b#c#kz', 3).
  • If no match exists, sub() returns the unchanged string.
  • If no match exists, subn() returns the unchanged string together with count 0.
  • Both functions support an optional count argument to limit the number of substitutions.

Important Notes:

  1. sub() and subn() are substitution functions of Python's re module.
  2. The first argument is the Regular Expression pattern.
  3. The second argument specifies the replacement.
  4. The third argument is the target string.
  5. sub() returns the resulting string after substitution.
  6. subn() returns a tuple rather than only the resulting string.
  7. The first item of the subn() tuple is the modified string.
  8. The second item is the number of replacements actually performed.
  9. subn() can be remembered as substitution + number.
  10. Only text matched by the Regular Expression is replaced.
  11. Non-matching text remains unchanged.
  12. If no matches exist, the target content remains unchanged.
  13. A no-match result from subn() has replacement count 0.
  14. The returned tuple from subn() can be accessed using indexes 0 and 1.
  15. The tuple can also be unpacked directly into two variables.
  16. The optional count argument can limit how many matches are replaced.
  17. If count is omitted or is 0, all non-overlapping matches are replaced.
  18. Do not confuse subn()'s replacement count with the number of characters in the resulting string.
📝 Key Takeaways
  • Substitution replaces the text matched by a Regular Expression with another text
  • re.sub() replaces every matching occurrence and returns the modified string
  • re.subn() returns a tuple containing the modified string and the number of replacements
  • The optional count parameter specifies the maximum number of replacements
  • If no match exists, sub() returns the original string and subn() returns (original_string, 0)

🧠 Test Your Knowledge

10 Questions
Progress: 0 / 10