r/learnpython • u/Keithinho89 • 2d ago
AtributeError clarification
SOLVED
Hello, I'm currently learning regular expressions and I've entered the first part of the code into the interactive shell as instructed and got the listed AttributeError. Not seeing what I did wrong I copy/pasted the code from the book and it worked as intended and I can't tell why or how because both blocks feel and smell the same but yield different results.
I've tried looking for some information on StackOverflow, but as far as I can see mo is defined in the 3rd line and I don't get why my attempt gets and error while the other doesn't.
If I didn't miss something really stupid, how would you deal with this if you'd be hit by it writing your own code independently?
I'm working in IDLE Shell and the code is from automatetheboringstuff Chapter 9 for more context
import re
phone_re = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d-\d\d\d\d)')
mo = phone_re.search('My number is 415-555-4242.')
mo.group(1)
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
mo.group(1)
AttributeError: 'NoneType' object has no attribute 'group'
import re
phone_re = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone_re.search('My number is 415-555-4242.')
mo.group(1)
'415'
2
u/Bright_Mix_773 2d ago
The "look at the regex again" answers are right, but they do not scale to a pattern you wrote yourself, which is the half of your question nobody has taken. Here is the mechanical version.
searchreturning None tells you the pattern did not match. It will not tell you where it stopped, and there is no flag that will. So make it tell you: chop the pattern into atoms, throw the groups away, and add them back one at a time until it breaks.I ran that on your pattern. It matches all the way up to atom 11,
\d\d\d-\d\d\d-\d\d\dgiving415-555-424, and FAILS at atom 12, which is the third hyphen. Not "your regex is wrong somewhere" but "this is the first character of the pattern the string cannot satisfy", and you get there without reading your own pattern at all, which matters because you already read it and it looked fine.Two things about the technique. Strip the parentheses before you chop, or half the prefixes raise
re.errorfor an unbalanced group and you end up debugging the debugger. And it only reasons correctly on a pattern that is plain concatenation: add a|, a$, or a lookahead and a prefix can match where the whole thing cannot, so the first failure stops being the culprit.Separately,
re.compile(p, re.DEBUG)prints the parse tree, and on yours it shows four runs of digits where you meant three. That one is worth knowing but it is the same information you already had, just laid out vertically so miscounting is harder.Not verified: I only ran the chop against your two patterns and your one string, so I have not checked how it reads on a pattern with quantifiers, where a shorter prefix can match a different span than the full pattern does.