replace part of path – python

Question:

Is there a quick way to replace part of the path in python?

for example:

old_path='/abc/dfg/ghi/f.txt'

I don’t know the beginning of the path (/abc/dfg/), so what I’d really like to tell python to keep everything that comes after /ghi/ (inclusive) and replace everything before /ghi/ with /jkl/mno/:

>>> new_path
    '/jkl/mno/ghi/f.txt/'
Asked By: HappyPy

||

Answers:

>>> import os.path
>>> old_path='/abc/dfg/ghi/f.txt'

First grab the relative path from the starting directory of your choice using os.path.relpath

>>> rel = os.path.relpath(old_path, '/abc/dfg/')
>>> rel
'ghi\f.txt'

Then add the new first part of the path to this relative path using os.path.join

>>> new_path = os.path.join('jklmno', rel)
>>> new_path
'jkl\mno\ghi\f.txt'
Answered By: Cory Kramer

If you’re using Python 3.4+, or willing to install the backport, consider using pathlib instead of os.path:

path = pathlib.Path(old_path)
index = path.parts.index('ghi')
new_path = pathlib.Path('/jkl/mno').joinpath(*path.parts[index:])

If you just want to stick with the 2.7 or 3.3 stdlib, there’s no direct way to do this, but you can get the equivalent of parts by looping over os.path.split. For example, keeping each path component until you find the first ghi, and then tacking on the new prefix, will replace everything before the last ghi (if you want to replace everything before the first ghi, it’s not hard to change things):

path = old_path
new_path = ''
while True:
    path, base = os.path.split(path)
    new_path = os.path.join(base, new_path)
    if base == 'ghi':
        break
new_path = os.path.join('/jkl/mno', new_path)

This is a bit clumsy, so you might want to consider writing a simple function that gives you a list or tuple of the path components, so you can just use find, then join it all back together, as with the pathlib version.

Answered By: abarnert

You can use the index of ghi:

old_path.replace(old_path[:old_path.index("ghi")],"/jkl/mno/")
In [4]: old_path.replace(old_path[:old_path.index("ghi")],"/jkl/mno/" )
Out[4]: '/jkl/mno/ghi/f.txt'
Answered By: Padraic Cunningham

A rather naive approach, but does the job:

Function:

def replace_path(path, frm, to):
    pre, match, post = path.rpartition(frm)
    return ''.join((to if match else pre, match, post))

Example:

>>> s = '/abc/dfg/ghi/f.txt'
>>> replace_path(s, '/ghi/', '/jkl/mno')
'/jkl/mno/ghi/f.txt'
>>> replace_path(s, '/whatever/', '/jkl/mno')
'/abc/dfg/ghi/f.txt'
Answered By: Jon Clements

The following is useful when you want to replace some known base directory in your path.

from pathlib import Path
old_path = Path('/abc/dfg/ghi/f.txt')
old_root = Path('/abc/dfg')
new_root = Path('/jkl/mno')
new_path = new_root / old_path.relative_to(old_root)
# Result: /jkl/mno/ghi/f.txt

I understand that the OP specifically mentioned that the path to the base directory is not known. However, since it is a common task to remove the path to the base directory, and the title of the question ("replace part of the path") is certainly bringing some folks with this subtype of problem here, I am posting it anyway.

Answered By: normanius

I needed to replace an arbitrary number of an arbitrary strings in a path
e.g. replace ‘package’ with foo in

VERSION_FILE = Path(f'{Path.home()}', 'projects', 'package', 'package', '_version.py')

So I use this call

_replace_path_text(VERSION_FILE, 'package', 'foo)

def _replace_path_text(path, text, replacement):
    parts = list(path.parts)
    new_parts = [part.replace(text, replacement) for part in parts]
    return Path(*new_parts)
Answered By: Psionman
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.