Using regular expressions can accomplish more complex text searches and replacements. This section introduces the rules for writing regular expressions. This content is the core of regular expressions and is basically the same across different programming languages.
Metacharacters
Metacharacters are characters in regular expressions that have special meanings beyond their literal sense. For example, in Python regular expressions, \d represents a digit, and \s represents whitespace. Common metacharacters are listed in Table 8-2.
Table 8-2 Common Metacharacters
| Metacharacter | Description | Metacharacter | Description |
|---|---|---|---|
| . | Matches any character except newline | ^ | Matches the start of a string |
| \w | Matches letters, digits, underscore, or Chinese characters | $ | Matches the end of a string |
| \s | Matches any whitespace | \n | Matches a newline |
| \d | Matches a digit | \r | Matches a carriage return |
| \b | Matches the start or end of a word | \t | Matches a tab |
Usually, we specify characters to find or search within a certain range, but sometimes the requirement is reversed — to exclude certain characters or search outside a character range. In such cases, we use metacharacters for negation, e.g., \D for non-digits, \S for non-whitespace. Common negating metacharacters are listed in Table 8-3.
Table 8-3 Common Negating Metacharacters
| Negating Metacharacter | Description |
|---|---|
| \W | Matches any character that is not a letter, digit, underscore, or Chinese character |
| \S | Matches any non-whitespace character |
| \D | Matches any non-digit character |
| \B | Matches a position that is not the start or end of a word |
| [^x] | Matches any character except x |
| [^aeiou] | Matches any character except a, e, i, o, u |
We now illustrate metacharacters with examples.
Given the original string "BC_101PW%", find the digits and replace them with an empty string (i.e., delete them).
【Excel VBA】
Sample file: Samples\ch20\Excel VBA\元字符.xlsm. The regular expression "\d" represents a single digit.
Sub Sam01()
Dim objReg As New RegExp
Dim strT As String
Dim mcT As MatchCollection
Dim matT As Match
strT = "BC_101PW%"
With objReg
.Global = True
.Pattern = "\d"
Set mcT = .Execute(strT)
Debug.Print .Replace(strT, "")
End With
For Each matT In mcT
If matT <> " " Then Debug.Print matT.Value
Next matT
End Sub
Running the procedure prints the replaced and found results in the Immediate Window:
BC_PW%
1
0
1
【Python】
In the Python shell:
>>> import re
>>> a = 'BC_101PW%'
>>> m0 = re.findall(r'\d', a)
>>> m0
['1', '0', '1']
>>> for i in m0:
... print(i)
...
1
0
1
>>> ms = re.sub(r'\d', '', a)
>>> ms
'BC_PW%'
Next example tests the metacharacter \b (word boundary), matching strings where C is at the start of the string or preceded by a space, followed by a digit. Replace matches with empty.
【Excel VBA】
Sub Sam02()
Dim objReg As New RegExp
Dim strT As String
strT = "C5dC56 C5"
With objReg
.Global = True
.Pattern = "\bC\d"
Debug.Print .Replace(strT, "")
End With
End Sub
Output in Immediate Window:
dC56
The first C5 is at the string start, satisfying C plus digit; the second C5 is preceded by a space, satisfying \b. Removing them leaves "dC56".
【Python】
>>> import re
>>> a = 'C5dC56 C5'
>>> m = re.sub(r'\bC\d', '', a)
>>> m
'dC56 '
The metacharacter ^ restricts matching to the very start of the string, e.g., ^\d means the string starts with a digit.
【Excel VBA】
Sub Sam03()
Dim objReg As New RegExp
Dim strT As String
strT = "12345my09"
With objReg
.Global = True
.Pattern = "^\d+"
Set mcT = .Execute(strT)
For Each matT In mcT
Debug.Print matT
Next matT
End With
End Sub
Output:
12345
Only "12345" at the start matches; "09" is not at the start. + means “one or more” of the preceding element (\d).
【Python】
>>> import re
>>> a = '12345my09'
>>> m = re.findall(r'^\d+', a)
>>> for i in m:
... print(i)
...
12345
\D indicates non-digit; $ forces match at end of string, e.g., C$ means last char is C.
【Excel VBA】
Sub Sam04()
Dim objReg As New RegExp
Dim strT As String
strT = "m12345my09W"
With objReg
.Global = True
.Pattern = "\d+\D$"
Set mcT = .Execute(strT)
For Each matT In mcT
Debug.Print matT
Next matT
End With
End Sub
Output:
09W
\d+\D$ matches digits followed by a non-digit at the string end.
【Python】
>>> import re
>>> a = 'm12345my09W'
>>> m = re.findall(r'\d+\D$', a)
>>> m
['09W']
Repetition
Sometimes we need to match multiple consecutive occurrences of a character type — this is repetition. The number of repetitions can be fixed or variable. In Python regex, \d+ means one or more digits (variable), \d{5} means exactly five digits (fixed).
Repetition metacharacters are listed in Table 8-4.
Table 8-4 Repetition Metacharacters
| Metacharacter | Description | Metacharacter | Description |
|---|---|---|---|
| * | Repeat 0 or more times | {n} | Repeat exactly n times |
| + | Repeat 1 or more times | {n,} | Repeat n or more times |
| ? | Repeat 0 or 1 time | {n,m} | Repeat between n and m times |
* = {0,} (zero or more). Example: find substrings starting with W followed by zero or more digits.
【Excel VBA】
Sub Sam08()
Dim objReg As New RegExp
Dim strT As String
strT = "W123YZW85CW0DFWU"
With objReg
.Global = True
.Pattern = "W\d*"
Set mcT = .Execute(strT)
For Each matT In mcT
Debug.Print matT
Next matT
End With
End Sub
Output:
W123
W85
W0
W
Last match is just W (no digits after).
【Python】
>>> import re
>>> a = 'W123YZW85CW0DFWU'
>>> m = re.findall(r'W\d*', a)
>>> m
['W123', 'W85', 'W0', 'W']
+ = {1,} (one or more). Example: W followed by one or more digits.
【Excel VBA】
Sub Sam081()
Dim objReg As New RegExp
Dim strT As String
strT = "W123YZW85CW0DFWU"
With objReg
.Global = True
.Pattern = "W\d+"
Set mcT = .Execute(strT)
For Each matT In mcT
Debug.Print matT
Next matT
End With
End Sub
Output:
W123
W85
W0
【Python】
>>> import re
>>> a = 'W123YZW85CW0DFWU'
>>> m = re.findall(r'W\d+', a)
>>> m
['W123', 'W85', 'W0']
? = {0,1}. Example: numbers with optional decimal point.
【Excel VBA】
Sub Sam09()
Dim objReg As New RegExp
Dim strT As String
strT = "W10.23RWA908C5..1"
With objReg
.Global = True
.Pattern = "\d+\.?\d+"
Set mcT = .Execute(strT)
For Each matT In mcT
Debug.Print matT
Next matT
End With
End Sub
Output:
10.23
908
Fixed repetition {n}: match exactly n repeats.
【Excel VBA】
Sub Sam10()
Dim objReg As New RegExp
Dim strT As String
strT = "WT123Pq89C"
With objReg
.Global = True
.Pattern = "\d{3}"
Debug.Print .Replace(strT, "")
End With
End Sub
Output:
WTPq89C
Range {n,m}: between n and m repeats.
【Excel VBA】
Sub Sam11()
Dim objReg As New RegExp
Dim strT As String
strT = "WT123Pq89C"
With objReg
.Global = True
.Pattern = "\d{2,3}"
Debug.Print .Replace(strT, "")
End With
End Sub
Output:
WTPqC
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'WT123Pq89C'
>>> re.sub(r'\d{2,}', '', a)
'WTPqC'
Character Classes
The previous methods can be used to find specified digits, letters, or whitespace. However, if a character set is given and the characters to be found must be either within this set or outside it, we need to use square brackets. The ways to define character sets with square brackets are shown in Table 8-5.
Table 8-5 Ways to Define Character Sets with Square Brackets
| Application Example | Description |
|---|---|
| [adwkf] | Find characters that are one of those inside the brackets |
| [^adwkf] | Find characters that are NOT any of those inside the brackets |
| [b-f] | Find characters that are one of b to f |
| [^b-f] | Find characters that are NOT any of b to f |
Continued Table
| Application Example | Description |
|---|---|
| [2-5] | Find characters that are one of 2 to 5 |
| [2-46-9] | Find characters that are one of 2-4 or 6-9 |
| [a-w2-5A-W] | Find characters that are one of a-w, 2-5, or A-W |
| [^一-龥] or [^\u4e00-\u9fa5] | Find non-Chinese characters (or characters not in the Chinese Unicode range) |
A character set enclosed in square brackets matches any single character within it. If [](@ref) is used, it matches any character outside the set (not matching characters inside the brackets).
Below is a string—we will find characters that match any character in the brackets.
【Excel VBA】
The sample file path is Samples\ch20\Excel VBA\Character Classes.xlsm.
Sub Sam15()
Dim objReg As New RegExp ' Create a regex object
Dim strT As String
strT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ' Given string
With objReg
.Global = True
.Pattern = "[AEIOU]" ' Regex: Match any character in the brackets
Debug.Print .Replace(strT, "") ' Delete matched characters
End With
End Sub
After running the procedure, the output in the Immediate Window is:
BCDFGHJKLMNPQRSTVWXYZ
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> re.sub('[AEIOU]', '', a)
'BCDFGHJKLMNPQRSTVWXYZ'
Now, find characters that do NOT match any character in the brackets.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Character Classes.xlsm.
Sub Sam16()
Dim objReg As New RegExp ' Output regex object(note: original typo "输出" → "Create")
Dim strT As String
strT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ' Given string
With objReg
.Global = True
.Pattern = "[^AEIOU]" ' Regex: Match characters NOT in the brackets
Debug.Print .Replace(strT, "") ' Delete matched characters
End With
End Sub
Output in Immediate Window:
AEIOU
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> re.sub(r'[^AEIOU]', '', a)
'AEIOU'
Given a string, find characters that fall within a specified range in the brackets.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Character Classes.xlsm.
Sub Sam17()
Dim objReg As New RegExp
Dim strT As String
strT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ' Given string
With objReg
.Global = True
.Pattern = "[G-T]" ' Regex: Match characters in the range G-T
Debug.Print .Replace(strT, "") ' Delete matched characters
End With
End Sub
Output in Immediate Window:
ABCDEFUVWXYZ
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> re.sub(r'[G-T]', '', a)
'ABCDEFUVWXYZ'
Find characters in the ranges 1–5 and G–T from a string.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Character Classes.xlsm.
Sub Sam18()
Dim objReg As New RegExp
Dim strT As String
strT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" ' Given string
With objReg
.Global = True
.Pattern = "[1-5G-T]" ' Regex: Match characters in 1-5 or G-T
Debug.Print .Replace(strT, "") ' Delete matched characters
End With
End Sub
Output in Immediate Window:
ABCDEFUVWXYZ67890
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
>>> re.sub(r'[1-5G-T]', '', a)
'ABCDEFUVWXYZ67890'
When finding Chinese characters in a string, use square brackets to specify the Chinese character range. There are two ways: [一-龥] (using Chinese character order) and [\u4e00-\u9fa5] (using Unicode hexadecimal codes). The latter uses 4-digit hex numbers: "一" (the first Chinese character) has the code \u4e00, and the last common Chinese character has the code \u9fa5.
Below is a string containing Chinese characters—we will find the Chinese characters and replace them with an empty string.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Character Classes.xlsm.
Sub Sam06()
Dim objReg As New RegExp
Dim strT As String
strT = "123 中 hwo 文 tr89 字符" ' Given string
With objReg
.Global = True
.Pattern = "[\u4e00-\u9fa5]" ' Regex: Specify Chinese range(alternative: "[一-龥]")
Debug.Print .Replace(strT, "") ' Delete matched Chinese characters
End With
End Sub
Output in Immediate Window:
123 hwo tr89
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = '123 中 hwo 文 tr89 字符'
>>> m = re.findall('[\u4e00-\u9fa5]', a)
>>> m
['中', '文', '字', '符']
>>> m = re.sub('[\u4e00-\u9fa5]', '', a)
>>> m
'123 hwo tr89 '
123 hwo tr89
8.2.4 Branch Conditions
Suppose there are multiple rules—matching any one of them completes the match. This requires branch conditions, which use | to separate different rules. For example, if a number is followed by a mass unit (some records as "公斤", others as "千克"), use \d+(公斤|千克) to extract it (equivalent to \d+公斤|\d+千克).
Below is a string where numbers are followed by "公斤", "kg", or "千克"—use branch conditions to write a regex for extraction.
Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Metacharacters.xlsm.
Sub Sam27()
' Omitted partial code...
strT = "10公斤 20kg 30千克" ' Given string
With objReg
.Global = True
.Pattern = "\d+(公斤|千克|kg)" ' Regex: Number followed by unit
'.Pattern = "\d+公斤|\d+千克|\d+kg" ' Equivalent writing
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT ' Output result
Next
End With
End Sub
Output in Immediate Window:
10公斤
20kg
30千克
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = '10公斤 20kg 30千克'
>>> m = re.finditer(r'\d+(公斤|千克|kg)', a)
>>> for i in m:
print(i.group(0))
10公斤
20kg
30千克
Capturing Groups and Non-Capturing Groups
Regular expressions may contain subexpressions (enclosed in parentheses), which are treated as a whole. For example, the regex "((ABC){2})" repeats "ABC" twice as a whole.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Groups.xlsm.
Sub Sam19()
Dim objReg As New RegExp
Dim strT As String
strT = "ABCABCWTU238" ' Given string
With objReg
.Global = True
.Pattern = "((ABC){2})" ' Regex: "ABC" repeated twice as a whole
Debug.Print .Replace(strT, "") ' Delete matched part
End With
End Sub
Output in Immediate Window:
WTU238
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'ABCABCWTU238'
>>> m = re.search('((ABC){2})', a)
>>> re.sub('((ABC){2})', '', a)
'WTU238'
When using parentheses to group regex, group numbers are automatically assigned (left-to-right, outer-to-inner). Group numbers allow backreferences to the corresponding group.
In the code below, the regex r"(WT)\d+\1" matches substrings where the start and end are "WT" with one or more digits in between. Note: \1 refers to the "WT" in the first parenthesis (group 1).
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Groups.xlsm.
Sub Sam20()
' Omitted partial code...
strT = "abcWT12389WT" ' Given string
With objReg
.Global = True
.Pattern = "(WT)\d+\1" ' Regex: Two "WT"s with digits in between
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT ' Output result
Next
End With
End Sub
Output in Immediate Window:
WT12389WT
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'abcWT12389WT'
>>> m = re.finditer(r'(WT)\d+\1', a)
>>> for i in m:
print(i.group())
WT12389WT
The match "WT12389WT" starts and ends with "WT" and has only digits in between—meeting the requirement.
The example below shows more groups. The regex r"((WT){2})((PR){2})\d+\2\4" has 4 pairs of parentheses (two layers on the left, two on the right). Let’s explore the group numbers:
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Groups.xlsm.
Sub Sam21()
' Omitted partial code...
strT = "abWTWTPRPR123WTPR56" ' Given string
With objReg
.Global = True
.Pattern = "((WT){2})((PR){2})\d+\2\4" ' Regex
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT
Debug.Print matT.SubMatches(0) ' Output submatch of group 0
Debug.Print matT.SubMatches(1) ' Group 1
Debug.Print matT.SubMatches(2) ' Group 2
Debug.Print matT.SubMatches(3) ' Group 3
Next
End With
End Sub
Output in Immediate Window:
WTWTPRPR123WTPR
WTWT
WT
PRPR
PR
The output shows group numbering follows left-to-right, outer-to-inner:
Left side: Outer parenthesis (WT){2} → group 1 ("WTWT"); inner parenthesis WT → group 2 ("WT").
Right side: Outer parenthesis (PR){2} → group 3 ("PRPR"); inner parenthesis PR → group 4 ("PR").
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'abWTWTPRPR123WTPR56'
>>> m = re.search(r'((WT){2})((PR){2})\d+\2\4', a)
>>> m.group(1)
'WTWT'
>>> m.group(2)
'WT'
>>> m.group(3)
'PRPR'
>>> m.group(4)
'PR'
Parentheses define capturing groups (saved in memory for later use). However, sometimes we don’t need to save the matched content—this is a non-capturing group. To create one, add ?: at the start of the parentheses (e.g., (?:\d{3})). Non-capturing groups do not get numbered or saved, saving memory and improving efficiency.
Below is a string with the regex r"(?:ab)(CD)\d+\1" (first group is non-capturing).
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Groups.xlsm.
Sub Sam22()
Dim objReg As New RegExp
Dim strT As String, mc, c
Dim m As Match
strT = "abCD123CDbc" ' Given string
With objReg
.Global = True
.Pattern = "(?:ab)(CD)\d+\1" ' Regex: First group is non-capturing
Set mc = .Execute(strT) ' Execute search
For Each m In mc ' Traverse results
Debug.Print m.Value ' Output matched value
Debug.Print m.SubMatches(0) ' Output first saved group
Next
End With
End Sub
Output in Immediate Window:
abCD123CD
CD
Since the first group is non-capturing, it is not numbered. Thus, the first saved group is "CD" (not "ab").
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = 'abCD123CDbc'
>>> m = re.finditer(r'(?:ab)(CD)\d+\1', a)
>>> for i in m:
print(i.group())
abCD123CD
Use re.finditer to get a match iterator and loop through results. The matched string includes "ab".
Use re.search to get a Match object and check its groups() attribute:
>>> m = re.search(r'(?:ab)(CD)\d+\1', a)
>>> m.groups()
('CD',)
Only one group is returned ("CD")—confirming the first group (non-capturing) is neither numbered nor saved.
Zero-Width Assertions
Zero-width assertions find content before or after a specified pattern (excluding the pattern itself). There are two types:
1. Zero-Width Positive Lookahead Assertion
Expression: (?=exp) — finds content before exp.
2. Zero-Width Positive Lookbehind Assertion
Expression: (?<=exp) — finds content after exp.
Combining both, we can find content between two patterns.
Below is a string—extract the number before "公斤" (unit: kilogram). Use zero-width positive lookahead.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Zero-Width Assertions.xlsm.
Sub Sam28()
' Omitted partial code...
strT = "10公斤 20公斤 30公斤" ' Given string
With objReg
.Global = True
.Pattern = "\d+(?=公斤)" ' Regex: Number before "公斤"(exclusive)
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT ' Output result
Next
End With
End Sub
Output in Immediate Window:
10
20
30
The regex r"\d+(?=公斤)" matches numbers before "公斤" (excluding "公斤")—correct.
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = '10公斤 20公斤 30公斤'
>>> m = re.finditer(r'\d+(?=公斤)x27;, a) # Extract only numbers before the unit
>>> for i in m:
print(i.group())
10
20
30
Below is a string—extract names after titles like "同学" (classmate), "战友" (comrade-in-arms), or "师兄" (senior). Use zero-width positive lookbehind.
>>> import re
>>> a = '同学李海 战友王刚 师兄张三'
>>> m = re.finditer(r'(?<=同学|战友|师兄)\w+', a) # Extract names after titles
>>> for i in m:
print(i.group())
李海
王刚
张三
The regex r"(?<=同学|战友|师兄)\w+" matches substrings after the titles (excluding the titles). Excel VBA cannot perform this operation.
Negative Zero-Width Assertions
Negative zero-width assertions assert that a position does NOT match a specified pattern. There are two types:
1. Zero-Width Negative Lookahead Assertion
Expression: (?!exp) — asserts the next content does NOT match exp.
2. Zero-Width Negative Lookbehind Assertion
Expression: (?<!exp) — asserts the previous content does NOT match exp.
Below is a string—match "123" where:
The preceding character is a letter, digit, or underscore (\w).
The following character is NOT a capital letter ([A-Z]).
Use zero-width negative lookahead.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Negative Zero-Width Assertions.xlsm.
Sub Sam31()
' Match "123" where the preceding is \w and the following is NOT [A-Z]
' Omitted partial code...
strT = "5123Wgh123hp123456" ' Given string
With objReg
.Global = True
.Pattern = "\w123(?![A-Z])" ' Regex: \w + "123" + not followed by [A-Z]
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT ' Output result
Next
End With
End Sub
Output in Immediate Window:
h123
p123
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = '5123Wgh123hp123456'
>>> m = re.finditer('\w123(?![A-Z])', a)
>>> for i in m:
print(i.group())
h123
p123
The first "123" is followed by "W" (capital letter)—so it does not match.
Greediness vs. Laziness
Previously, * and + match as many characters as possible (greedy matching). Sometimes we need to match as few as possible (lazy matching). Add a ? after the greedy quantifier to make it lazy.
Common lazy matching formats are shown in Table 8-6.
Table 8-6 Common Lazy Matching Formats
| Lazy Matching Format | Description |
|---|---|
| *? | Repeat any number of times, but as few as possible |
| +? | Repeat one or more times, but as few as possible |
| ?? | Repeat zero or one time, but as few as possible |
| {n,m}? | Repeat n to m times, but as few as possible |
| {n,}? | Repeat n or more times, but as few as possible |
Below is a string—compare greedy and lazy matching results.
【Excel VBA】
Sample file path: Samples\ch20\Excel VBA\Greediness and Laziness.xlsm.
Sub Sam32()
' Omitted partial code...
strT = " 123 abc53 59wt " ' Given string
With objReg
.Global = True
.Pattern = "\s.+?\s" ' Regex: Lazy matching(space + minimal chars + space)
Set mcT = .Execute(strT) ' Execute search
For Each matT In mcT ' Traverse results
Debug.Print matT ' Output result
Next
End With
End Sub
Output in Immediate Window:
123
abc53
59wt
The regex "\s.+?\s" uses +? (lazy matching)—matches minimal characters between spaces, resulting in 3 substrings separated by spaces.
【Python】
Enter the following content in the Python Shell window:
>>> import re
>>> a = ' 123 abc53 59wt '
>>> m = re.finditer('\s.+\sx27;, a) # Greedy matching(no ?)
>>> for i in m:
print(i.group())
123 abc53 59wt
The regex "\s.+\s" uses + (greedy matching)—matches all characters between the first and last space, resulting in the entire string.
>>> m = re.finditer('\s.+?\sx27;, a) # Lazy matching(+?)
>>> for i in m:
print(i.group())
123
abc53
59wt
The regex "\s.+?\s" uses +? (lazy matching)—matches minimal characters between spaces, resulting in 3 substrings.