Omar Younis
Omar Younis

Reputation: 65

Removing numbers and spaces in multiple file names with Python

I am trying to rename multiple mp3 files I have in a folder. They start with something like "1 Hotel California - The Eagles" and so on. I would like it to be just "Hotel California - The Eagles". Also, there could be a "05 Hotel California - The Eagles" as well, which means removing the number from a different files would create duplicates, which is the problem I am facing. I want it to replace existing files/overwrite/delete one of them or whatever a solution might be. P.S, Adding "3" to the "1234567890 " would remove the "3" from the .mp3 extension

I am new to python, but here is the code I am using to implement this

    import os


    def renamefiles():

        list = os.listdir(r"E:\NEW")
        print(list)
        path = os.getcwd()
        print(path)
        os.chdir(r"E:\NEW")
        for name in list:
            os.rename(name, name.translate(None, "124567890 "))
        os.chdir(path)

    renamefiles()

And here is the error I get WindowsError: [Error 183] Cannot create a file when that file already exists

Any help on how I could rename the files correctly would be highly appreciated!

Upvotes: 2

Views: 5608

Answers (6)

The Real Codeslinger
The Real Codeslinger

Reputation: 312

You just need to change directory to where *.mp3 files are located and execute 2 lines of below with python:

import os,re
for filename in os.listdir():
    os.rename(filename, filname.strip(re.search("[0-9]{2}", filename).group(0)))

Upvotes: 0

userABC123
userABC123

Reputation: 1500

I was unable to easily get any of the answers to work with Python 3.5, so here's one that works under that condition:

import os
import re


def rename_files():
    path = os.getcwd()
    file_names = os.listdir(path)
    for name in file_names:
        os.rename(name, re.sub("[0-9](?!\d*$)", "", name))

rename_files()

This should work for a list of files like "1 Hotel California - The Eagles.mp3", renaming them to "Hotel California - The Eagles.mp3" (so the extension is untouched).

Upvotes: 2

bruno desthuilliers
bruno desthuilliers

Reputation: 77902

Ok so what you want is:

  • create a new filename removing leading numbers
  • if that new filename exists, remove it
  • rename the file to that new filename

The following code should work (not tested).

import os
import string

class FileExists(Exception):
    pass

def rename_files(path, ext, remove_existing=True):
    for fname in os.listdir(path):
        # test if the file name ends with the expected 
        # extension else skip it
        if not fname.endswith(ext):
            continue

        # chdir is not a good idea, better to work
        # with absolute path whenever possible
        oldpath = os.path.join(path, fname)
        # remove _leading_ digits then remove all whitespaces
        newname = fname.lstrip(string.digits).strip()
        newpath = os.path.join(path, newname)
        # check if the file already exists
        if os.path.exists(newpath):
            if remove_existing:
                # it exists and we were told to
                # remove existing file:
                os.remove(newpath)
            else:
                # it exists and we were told to
                # NOT remove existing file:
                raise FileExists(newpath)
        # ok now we should be safe
        os.rename(oldpath, newpath)

# only execute the function if we are called directly
# we dont want to do anything if we are just imported
# from the Python shell or another script or module
if __name__ == "__main__":
    # exercice left to the reader:
    # add command line options / arguments handling
    # to specify the path to browse, the target 
    # extension and whether to remove existing files
    # or not
    rename_files(r"E:\NEW", ".mp3", True)

Upvotes: 0

Padraic Cunningham
Padraic Cunningham

Reputation: 180401

You can catch an OSError and also use glob to find the .mp3 files:

import os
from glob import iglob

def renamefiles(pth):
    os.chdir(pth)
    for name in iglob("*.mp3"):
        try:
            os.rename(name, name.translate(None, "124567890").lstrip())
        except OSError:
            print("Caught error for {}".format(name))
            # os.remove(name) ?

What you do when you catch the error is up to you, you could keep some record of names found and increment a count for each or leave as is.

If the numbers are always at the start you can also just lstrip then away so you can then use 3 safely:

 os.rename(name, name.lstrip("0123456789 "))

using one of your example strings:

In [2]: "05 Hotel California - The Eagles.mp3".lstrip("01234567890 ")
Out[2]: 'Hotel California - The Eagles.mp3'

Using your original approach could never work as desired as you would remove all spaces:

In [3]: "05 Hotel California - The Eagles.mp3".translate(None,"0124567890 ")
Out[3]: 'HotelCalifornia-TheEagles.mp3'

If you don't care what file gets overwritten you can use shutil.move:

import os
from glob import iglob
from shutil import move

def renamefiles(pth):
    os.chdir(pth)
    for name in iglob("*.mp3"):
        move(name, name.translate(None, "124567890").lstrip())

On another note, don't use list as a variable name.

Upvotes: 2

R Nar
R Nar

Reputation: 5515

instead of using name.translate, import the re lib (regular expressions) and use something like

"(?:\d*)?\s*(.+?).mp3"

as your pattern. You can then use

Match.group(1)

as your rename.

For dealing with multiple files, add an if statement that checks if the file already exists in the library like this:

os.path.exists(dirpath)

where dirpath is the directory that you want to check in

Upvotes: 2

ShadowRanger
ShadowRanger

Reputation: 155363

You need to verify that the names being changed actually changed. If the name doesn't have digits or spaces in it, the translate will return the same string, and you'll try to rename name to name, which Windows rejects. Try:

for name in list:
    newname = name.translate(None, "124567890 ")
    if name != newname:
        os.rename(name, newname)

Note, this will still fail if the file target exists, which you'd probably want if you were accidentally collapsing two names into one. But if you want silent replace behavior, if you're on Python 3.3 or higher, you can change os.rename to os.replace to silently overwrite; on earlier Python, you can explicitly os.remove before calling os.rename.

Upvotes: 4

Related Questions