In regular expressions, the quantifiers *, +, and ? are greedy by default, which means that they will match as much as possible. However, you can also use the *?, +?, and ?? syntax to make them non-greedy, which means that they will match as little as possible.

Here's an example to illustrate the difference between greedy and non-greedy matching:

import re
 
text = "<html><head><title>Title</title></head><body>Body</body></html>"
pattern1 = "<.*>"  # Greedy match
pattern2 = "<.*?>"  # Non-greedy match
 
matches1 = re.findall(pattern1, text)
matches2 = re.findall(pattern2, text)
 
print("Greedy matches:", matches1)
print("Non-greedy matches:", matches2)

In this example, we are trying to match the HTML tags in the given text using two different patterns. The first pattern is a greedy match, which uses the * quantifier to match any number of characters between the < and > characters. The second pattern is a non-greedy match, which uses the *? quantifier to match as few characters as possible between the < and > characters.

The output of this program is:

Greedy matches: ['<html><head><title>Title</title></head><body>Body</body></html>']
Non-greedy matches: ['<html>', '<head>', '<title>', '</title>', '</head>', '<body>', '</body>', '</html>']

As you can see, the greedy match matches the entire HTML document, while the non-greedy match matches each individual HTML tag separately.

You can use the non-greedy matching syntax with any quantifier, as well as with other regular expression syntax such as character classes, grouping with parentheses, and alternation with the | operator.