1

What would be the best way to change a single directory name (only the first occurence) within a path?

Example:

source_path = "/path/to/a/directory/or/file.txt"
target_path = "/path/to/different/directory/or/file.txt"

I this case, the instruction would be: "replace the first directory of the name 'a' with a directory of the name 'different'"

I can think of methods where I would split up the path in its single parts first, then find the first "a", replace it and join it again. But I wonder if there is a more elegant way to deal with this. Maybe a built-in python function.

5 Answers 5

2

There is a function called os.path.split that can split a path into the final part and all leading up to it but that's the closest your going to get. Therefore the most elegant thing we can do is create a function that calls that continuously:

import os, sys 
def splitall(path): 
    allparts = [] 
    while 1: 
        parts = os.path.split(path) 
        if parts[0] == path: # sentinel for absolute paths 
            allparts.insert(0, parts[0]) 
            break 
        elif parts[1] == path: # sentinel for relative paths 
            allparts.insert(0, parts[1]) 
            break 
        else: 
            path = parts[0] 
            allparts.insert(0, parts[1]) 
            return allparts

Then you could use it like this, joining back together with os.path.join:

>>> source_path = '/path/to/a/directory/or/file'
>>> temp = splitall(source_path)
>>> temp
['path', 'to', 'a', 'directory', 'or', 'file']
>>> temp[2] = 'different'
>>> target_path = os.path.join(*temp)
>>> target_path
'path/to/different/directory/or/file'
1
  • Thanks! Ok, I guess this really is the simplest approach after all.
    – basilikum
    Commented Mar 17, 2014 at 9:08
0

If I understand what you want to say, you want this:

source_path = "/path/to/a/directory/or/file.txt"
target_path = source_path.replace("/a/", "/different/", 1)
print target_path
2
  • Ok, yes, that's true. But I was hoping to avoid "low-level" string operations that contain explicit slashs.
    – basilikum
    Commented Mar 16, 2014 at 23:01
  • Well, you can use regex to do it. Commented Mar 16, 2014 at 23:05
0

Use https://docs.python.org/3/library/pathlib.html#module-pathlib:

>>> from pathlib import PurePath
>>> import os
>>> path = PurePath("/path/to/a/directory/or/file.txt")
>>> path.parts
('/', 'path', 'to', 'a', 'directory', 'or', 'file.txt')
>>> a_idx = -1
>>> for idx,part in enumerate(path.parts):
...   if part == 'a':
...     a_idx = idx
...     break
... 
>>> a_idx
3
>>> pre_path = os.path.join(*path.parts[:a_idx])
>>> post_path = os.path.join(*path.parts[a_idx+1:])
>>> new_path = os.path.join(pre_path, 'different', post_path)
>>> new_path
'/path/to/different/directory/or/file.txt'
0

In case you don't know the name of the directory, but only its index:

from pathlib import Path

source_path = Path("/path/to/a/directory/or/file.txt")
unknown_name = source.parts[3] # position including root
target_path = "/".join([part if part != unknown_name else "different" for part in source.parts])[1:]

In case you know the name of the directory but not its index, almost the same:

from pathlib import Path

source = Path("/path/to/a/directory/or/file.txt")
src_parts = source.parts
unknown_index = src_parts.index('a')
target_path = "/".join([src_parts[part] if part != unknown_index else "different" for part in range(len(src_parts))])[1:]
0

Just to complete anon582847382 answer. If it is preferable to you to not pass by a custom splitall function:

path = os.path.normpath(path)
path.split(os.sep)

Not the answer you're looking for? Browse other questions tagged or ask your own question.