This tutorial is all about the AND operator of Python’s
If you’ve been reading this carefully, you may ask: “WHAT — why is there an AND operator for regular expressions?” (And rightly so.)
Sure, there’s the OR operator (example:
'iPhone|iPad'). But what’s the meaning of matching one regular expression AND another?
There are different interpretations for the AND operator in a regular expression (regex):
- Ordered AND Regex: Match two patterns in order, i.e., first pattern
A, and second pattern
B. Technically, you’d use the pattern
ABto match both in order.
- Unordered AND Regex: Match multiple patterns in a string but in no particular order (source). In this case, you’ll use a bag-of-words approach.
I’ll discuss both approaches in the following. (You can also watch the video as you read the tutorial.)
👉 Related article: Python Regex Superpower – The Ultimate Guide
Ordered Python Regex AND Operator
💬 Question: Given a string. Your goal is to find all substrings matching string
'iPhone', followed by string
'iPad'. You can view this as the AND operator of two regular expressions. How to achieve this?
The straightforward AND operation of both strings is the regular expression pattern
In the following example, you want to match pattern
'aaa' and pattern
'bbb'—in this order.
>>> import re >>> text = 'aaabaaaabbb' >>> A = 'aaa' >>> B = 'bbb' >>> re.findall(A+B, text) ['aaabbb'] >>>
You use the
re.findall() method. In case you don’t know it, here’s the definition from the Finxter blog article:
ℹ️ Info: The
re.findall(pattern, string) function finds all occurrences of the
pattern in the
string and returns a list of all matching substrings.
👉 Recommended Tutorial: Please consult the blog article to learn everything you need to know about this fundamental Python method.
The first argument is the pattern
A+B which evaluates to
'aaabbb'. There’s nothing fancy about this: each time you write a string consisting of more than one character, you essentially use the ordered AND operator.
The second argument is the text
'aaabaaaabbb' which you want to search for the pattern.
The result shows that there’s a matching substring in the text:
Unordered Python Regex AND Operator
💬 Question: But what if you want to search a given text for pattern
A AND pattern
B—but in no particular order? In other words: if both patterns appear anywhere in the string, the whole string should be returned as a match.
Now, this is a bit more complicated because any regular expression pattern is ordered from left to right.
A simple solution is to use the lookahead assertion
(?.*A) to check whether regex
A appears anywhere in the string.
Note we assume a single line string as the dot/asterisk
.* pattern doesn’t match the newline character by default.
Let’s first have a look at the minimal solution to check for two patterns anywhere in the string (say, patterns
>>> import re >>> pattern = '(?=.*hi)(?=.*you)' >>> re.findall(pattern, 'hi how are yo?')  >>> re.findall(pattern, 'hi how are you?') ['']
In the first example, both words do not appear. In the second example, they do.
But how does the lookahead assertion work?
You must know that any other regex pattern “consumes” the matched substring. The consumed substring cannot be matched by any other part of the regex.
ℹ️ Info: Think of the lookahead assertion as a non-consuming pattern match.
- The regex engine goes from the left to the right—searching for the pattern.
- At each point, it has one “current” position to check if this position is the first position of the remaining match.
- In other words, the regex engine tries to “consume” the next character as a (partial) match of the pattern.
The advantage of the lookahead expression is that it doesn’t consume anything. It just “looks ahead” starting from the current position whether what follows would theoretically match the lookahead pattern. If it doesn’t, the regex engine cannot move on.
Let’s go back to the expression
(?=.*hi)(?=.*you) to match strings that contain both
'you'. Why does it work?
The reason is that the lookahead expressions don’t consume anything. You first search for an arbitrary number of characters
.*, followed by the word
But because the regex engine hasn’t consumed anything, it’s still at the same position at the beginning of the string. So, you can repeat the same for the word
Note that this method doesn’t care about the order of the two words:
>>> import re >>> pattern = '(?=.*hi)(?=.*you)' >>> re.findall(pattern, 'hi how are you?') [''] >>> re.findall(pattern, 'you are how? hi!') ['']
No matter which word
"you" appears first in the text, the regex engine finds both.
💬 Question: You may ask, why’s the output the empty string?
The reason is that the regex engine hasn’t consumed any character. It just checked the lookaheads. So the easy fix is to consume all characters as follows:
>>> import re >>> pattern = '(?=.*hi)(?=.*you).*' >>> re.findall(pattern, 'you fly high') ['you fly high']
Now, the whole string is a match because after checking the lookahead with
'(?=.*hi)(?=.*you)', you also consume the whole string
Before I let you go, allow me to provide you a couple of additional nuances of regex pattern matching in Python. Please? 🙏
Python Regex Not
How can you search a string for substrings that do NOT match a given pattern? In other words, what’s the “negative pattern” in Python regular expressions?
The answer is two-fold:
- If you want to match all characters except a set of specific characters, you can use the negative character class
- If you want to match all substrings except the ones that match a regex pattern, you can use the feature of negative lookahead
Here’s an example for the negative character class:
>>> import re >>> re.findall('[^a-m]', 'aaabbbaababmmmnoopmmaa') ['n', 'o', 'o', 'p']
And here’s an example of the negative lookahead pattern to match all “words that are not followed by words”:
>>> re.findall('[a-z]+(?![a-z]+)', 'hello world') ['hello', 'world']
The negative lookahead
(?![a-z]+) doesn’t consume (match) any character. It just checks whether the pattern
[a-z]+ does NOT match at a given position. The only times this happens is just before the empty space and the end of the string.
[Collection] What Are The Different Python Re Quantifiers?
The “and”, “or”, and “not” operators are not the only regular expression operators you need to understand. So what are other operators?
Next, you’ll get a quick and dirty overview of the most important regex operations and how to use them in Python. Here are the most important regex quantifiers:
|The wild-card (‘dot’) matches any character in a string except the newline character ‘n’.||Regex ‘…’ matches all words with three characters such as ‘abc’, ‘cat’, and ‘dog’.|
|The zero-or-more asterisk matches an arbitrary number of occurrences (including zero occurrences) of the immediately preceding regex.||Regex ‘cat*’ matches the strings ‘ca’, ‘cat’, ‘catt’, ‘cattt’, and ‘catttttttt’.|
|The zero-or-one matches (as the name suggests) either zero or one occurrences of the immediately preceding regex.||Regex ‘cat?’ matches both strings ‘ca’ and ‘cat’ — but not ‘catt’, ‘cattt’, and ‘catttttttt’.|
|The at-least-one matches one or more occurrences of the immediately preceding regex.||Regex ‘cat+’ does not match the string ‘ca’ but matches all strings with at least one trailing character ‘t’ such as ‘cat’, ‘catt’, and ‘cattt’.|
|The start-of-string matches the beginning of a string.||Regex ‘^p’ matches the strings ‘python’ and ‘programming’ but not ‘lisp’ and ‘spying’ where the character ‘p’ does not occur at the start of the string.|
|The end-of-string matches the end of a string.||Regex ‘py$’ would match the strings ‘main.py’ and ‘pypy’ but not the strings ‘python’ and ‘pypi’.|
|The OR matches either the regex A or the regex B. Note that the intuition is quite different from the standard interpretation of the or operator that can also satisfy both conditions.||Regex ‘(hello)|(hi)’ matches strings ‘hello world’ and ‘hi python’. It wouldn’t make sense to try to match both of them at the same time.|
|The AND matches first the regex A and second the regex B, in this sequence.||We’ve already seen it trivially in the regex ‘ca’ that matches first regex ‘c’ and second regex ‘a’.|
Note that I gave the above operators some more meaningful names (in bold) so that you can immediately grasp the purpose of each regex. For example, the ‘^’ operator is usually denoted as the ‘caret’ operator. Those names are not descriptive so I came up with more kindergarten-like words such as the “start-of-string” operator.
We’ve already seen many examples but let’s dive into even more!
import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' print(re.findall('.a!', text)) ''' Finds all occurrences of an arbitrary character that is followed by the character sequence 'a!'. ['Ha!'] ''' print(re.findall('is.*and', text)) ''' Finds all occurrences of the word 'is', followed by an arbitrary number of characters and the word 'and'. ['is settled, and'] ''' print(re.findall('her:?', text)) ''' Finds all occurrences of the word 'her', followed by zero or one occurrences of the colon ':'. ['her:', 'her', 'her'] ''' print(re.findall('her:+', text)) ''' Finds all occurrences of the word 'her', followed by one or more occurrences of the colon ':'. ['her:'] ''' print(re.findall('^Ha.*', text)) ''' Finds all occurrences where the string starts with the character sequence 'Ha', followed by an arbitrary number of characters except for the new-line character. Can you figure out why Python doesn't find any?  ''' print(re.findall('n$', text)) ''' Finds all occurrences where the new-line character 'n' occurs at the end of the string. ['n'] ''' print(re.findall('(Life|Death)', text)) ''' Finds all occurrences of either the word 'Life' or the word 'Death'. ['Life', 'Death'] '''
In these examples, you’ve already seen the special symbol ‘n’ which denotes the new-line character in Python (and most other languages). There are many special characters, specifically designed for regular expressions. Next, we’ll discover the most important special symbols.
Related Re Methods
There are seven important regular expression methods which you must master:
re.findall(pattern, string)method returns a list of string matches. Read more in our blog tutorial.
re.search(pattern, string)method returns a match object of the first match. Read more in our blog tutorial.
re.match(pattern, string)method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
re.fullmatch(pattern, string)method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
re.compile(pattern)method prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code. Read more in our blog tutorial.
re.split(pattern, string)method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those. Read more in our blog tutorial.
re.sub(The re.sub(pattern, repl, string, count=0, flags=0)method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in our blog tutorial.
These seven methods are 80% of what you need to know to get started with Python’s regular expression functionality.
Where to Go From Here?
You’ve learned everything you need to know about the Python Regex AND Operator.
There are different interpretations for the AND operator in a regular expression (regex):
- Ordered: Match one regex pattern after another. In other words, you first match pattern
AAND then you match pattern
B. Here the answer is simple: you use the pattern
ABto match both.
- Unordered: Match multiple patterns in a string but in no particular order. In this case, you’ll use a bag-of-words approach.
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can certainly become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!
[Webinar] Become a Six-Figure Freelance Developer with Python
Join us. It’s fun! 🙂
While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.
To help students reach higher levels of Python success, he founded the programming education website Finxter.com that has taught exponential skills to millions of coders worldwide. He’s the author of the best-selling programming books Python One-Liners (NoStarch 2020), The Art of Clean Code (NoStarch 2022), and The Book of Dash (NoStarch 2022). Chris also coauthored the Coffee Break Python series of self-published books. He’s a computer science enthusiast, freelancer, and owner of one of the top 10 largest Python blogs worldwide.
His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.