Reputation: 37
I'm trying to rename some files which all start with the same string (Vertragshandbuch_Beitrag_) in a folder using pyhton on windows.
An example file-name: Vertragshandbuch_Beitrag_004_Term Sheet.docx
New file-name should look like this: 4.docx
My current code looks like this:
import os
import re
for filename in os.listdir("."):
m = re.match("Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx", filename)
number = m.group(1)
new_filename = number + ".docx"
os.rename(filename, new_filename)
print(new_filename)
I'm getting this error: Traceback (most recent call last): File "C:(...)rename.py", line 6, in number = m.group(1) AttributeError: 'NoneType' object has no attribute 'group'
I checked the regex with several filenames here: https://regex101.com/ and it was always a perfect match.
I'm new to python and before asking the question I searched a long time and all the tips about normalizing the file name didn't help.
I changed the script after input from blurp to:
import os
import re
for filename in os.listdir("."):
m = re.match(r'Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx', filename)
number = m.group(1)
new_filename = number + ".docx"
os.rename(filename, new_filename)
print(new_filename)
Still the same error and still a match when I check the regex.
To test the regex match I used now:
import os
import re
for filename in os.listdir("."):
m = re.match(r'Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx', filename)
number = m.group(1)
new_filename = number + ".docx"
if m is not None:
os.rename(filename, new_filename)
print(new_filename)
Still same error message.
Okay, as a last resort I tried this in a folder which contained only the file Vertragshandbuch_Beitrag_003_Letter.docx:
import os, sys
import re
for filename in os.listdir("."):
m = re.match(r"Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx", filename)
print(m)
I got the following result: <_sre.SRE_Match object; span=(0, 40), match='Vertragshandbuch_Beitrag_003_Letter.docx'>
Looks like it is matching, still the error.
Upvotes: 2
Views: 1411
Reputation: 1499
If you'd prefer, you can also make your matches optional. This way, you will get a match object (not None
), even if your string does not match.
Putting this on top, because it's very important:
.*
and similar will run over optional matches, so this will not work if you don't know what might be surrounding the substring you'd like to capture.
That being said, here's the usual behavior.
>>> re.match('(a)', a).groups()
('a',)
>>> re.match('(a)', b).groups()
AttributeError: 'NoneType' object has no attribute 'groups'
A ?
after the parenthesis makes the match for 'a' optional.
>>> re.match('(a)?', 'a').groups()
('a',)
>>> re.match('(a)?', 'b').groups()
(None,)
You can even pass a default value to groups
.
re.match('(a)?', 'a').groups('cannot find a')
('a',)
re.match('(a)?', 'b').groups('cannot find a')
('cannot find a',)
This can sometimes make for more readable code.
Upvotes: 0
Reputation: 1955
When you call re.match()
if the string supplied doesn't match the regex pattern, it will equal None
.
What I'm assuming the problem is, is that you are coming across a filename that doesn't match the regex pattern you have supplied.
Even if the regex matches your files correctly, the first time re.match()
returns None
it will break unless you explicitly catch it. Otherwise, when you call re.match().group()
, it doesn't exist and it raises an error.
This worked for me when I made files with the name format specified:
import os
import re
def rename_num(path):
# Create a pattern to match filenames to
match_pattern = r"Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx"
pattern = re.compile(match_pattern)
# For each file in the path supplied above
for filename in os.listdir(path):
# Use the re module to match the regex pattern to the filename.
# If the filename doesn't match the regex found will be equal to None.
found = pattern.match(filename)
# If found is not equal to None, print the filename, groups and rename the file
if found:
os.rename(os.path.join(path, filename), os.path.join(path, found.group(1) + ".docx"))
print("{} renamed to {}".format(filename, found.group(1) + ".docx"))
# To run the above method in the directory the script is in:
p = os.path.abspath(os.path.dirname(__file__))
rename_num(p)
I created files with names like you supplied (numbers 001 - 007) and
this was my output:
Vertragshandbuch_Beitrag_001_Term Sheet.docx renamed to 001.docx Vertragshandbuch_Beitrag_002_Term Sheet.docx renamed to 002.docx Vertragshandbuch_Beitrag_003_Term Sheet.docx renamed to 003.docx Vertragshandbuch_Beitrag_004_Term Sheet.docx renamed to 004.docx Vertragshandbuch_Beitrag_005_Term Sheet.docx renamed to 005.docx Vertragshandbuch_Beitrag_006_Term Sheet.docx renamed to 006.docx Vertragshandbuch_Beitrag_007_Term Sheet.docx renamed to 007.docx
I hope this helps.
Upvotes: 2