Skip to content

Instantly share code, notes, and snippets.

@FichteFoll
Created June 3, 2012 17:27
Show Gist options
  • Save FichteFoll/2864277 to your computer and use it in GitHub Desktop.
Save FichteFoll/2864277 to your computer and use it in GitHub Desktop.
A small script I use for batch-renaming files and/or folders with Regular Expressions
# A list of dicts will be run over every file or directory in the "current" directory.
# TODO:
# - 'directory' option: Use specified dir as "parent"
# - 'subdirs' option: Scan through subdirs (don't play with self-refering Junctions, if that's even possible)
import os
import re
regs = [
# dict(
# test=r'', # regexp to test whether a renaming should take place at all; optinal (usually not necessary)
# match=r'', # rexexp
# repl=r'', # string or function
# type='all' # or 'file' or 'dir'; optional
# num=3 # number of replacements; optional (usually not necessary)
# }
# examples:
# dict(
# match=r'^.*? - (?P<album>.*) \(.*?(?P<year>\d+)\)',
# repl=r'\g<year> - \g<album>',
# type='dir'
# )
# dict(
# match=r'^(\[biribiri\])\s+(.*)',
# repl=r'\2 \1',
# type='dir'
# )
dict(
match=r'(.*)',
repl=r'\1',
type='all'
)
]
print("Parsing regs...")
regs_count_old = len(regs)
# compile regexps
regex_class = re.compile(".").__class__
compile_tuple = ('match', 'test')
reg_count = 0
for reg in regs:
for key in compile_tuple:
if key in reg:
try:
reg[key] = re.compile(reg[key])
except Exception as e: # re.error, TypeError
print(("\t[Error] regs[%d]%s:\n" +
"\t Unable to compile %r:\n" +
"\t [Errstr]: %s\n" +
"\t Removing...")
% (reg_count
, 'match' in reg
and (
not isinstance(reg['match'], regex_class)
and " = `%s`" % reg['match'] # cast to string if necessary
or " = `%s`" % reg['match'].pattern
) or ''
, key
, e)
)
regs.remove(reg)
reg_count += 1
# test dicts in 'regs' for validness
reg_count = -1
for reg in regs:
reg_count += 1
if 'match' not in reg:
print(("\t[Error] regs[%d]:\n" +
"\t 'match' not specified! Removing...")
% reg_count)
regs.remove(reg)
continue
if 'repl' not in reg:
print(("\t[Error] regs[%d] = `%s`:\n"
"\t 'repl' not specified! Removing...")
% (reg_count, reg['match'].pattern))
regs.remove(reg)
continue
if 'type' in reg and reg['type'] not in ("all", "file", "dir"):
print(("\t[Error] regs[%d] = `%s`:\n"
"\t Value of 'type' is not valid! Assuming 'all'...")
% (reg_count, reg['match'].pattern))
del reg['type']
regs_count = len(regs)
print("Removed %d regs out of %d (%d left)" % (regs_count - regs_count, regs_count_old, regs_count))
print("Starting with applying...")
# Do the renaming
matching_regs = 0
reg_count = 0
rename_count_total = 0
for reg in regs:
print("Parsing regs[%s]: `%s`->%s..."
% (reg_count,
reg['match'].pattern,
'`' + reg['repl'] + '`' if not callable(reg['repl']) else 'function')
)
files = os.listdir()
rename_count = 0
for filename in files:
# test 'type'
if 'type' in reg:
if os.path.isdir(filename):
if reg['type'] == "file":
continue
else:
if reg['type'] == "dir":
continue
# apply 'test'
if 'test' in reg and not reg['test'].search(filename):
continue
# the regex
new_filename = reg['match'].sub(reg['repl'], filename, reg.get('count', 0))
if new_filename != filename:
print("\tRenaming `%s` to `%s`..." % (filename, new_filename))
try:
os.rename(filename, new_filename)
except OSError as e:
print(("\t[Error] while renaming"
"\t [Errno]: %d, [Errstr]: %s")
% (filename, new_filename,
e.errno, e.strerror)
)
else:
rename_count += 1
print("\tRenamed %d files or dirs" % rename_count)
matching_regs += rename_count > 0
rename_count_total += rename_count
print("Renamed %d files or dirs in total" % rename_count_total)
print("%d regexps actually matched" % matching_regs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment