IT박스

os / path 형식에 관계없이 경로에서 파일 이름 추출

itboxs 2020. 10. 2. 21:50
반응형

os / path 형식에 관계없이 경로에서 파일 이름 추출


운영 체제 또는 경로 형식이 무엇이든 상관없이 경로에서 파일 이름을 추출하는 데 사용할 수있는 Python 라이브러리는 무엇입니까?

예를 들어,이 모든 경로가 나를 반환하고 싶습니다 c.

a/b/c/
a/b/c
\a\b\c
\a\b\c\
a\b\c
a/b/../../a/b/c/
a/b/../../a/b/c

사용 os.path.split또는 os.path.basename다른 사람이 모든 경우에하지 않습니다 작업을 제안 같이 리눅스에서 스크립트를 실행하고 고전적인 윈도우 스타일의 경로를 처리하려고 시도하는 경우, 실패합니다.

Windows 경로는 경로 구분 기호로 백 슬래시 또는 슬래시를 사용할 수 있습니다. 따라서 ntpath모듈 (Windows에서 실행할 때 os.path와 동일 함)은 모든 플랫폼의 모든 (1) 경로에서 작동 합니다.

import ntpath
ntpath.basename("a/b/c")

물론 파일이 슬래시로 끝나는 경우 기본 이름은 비어 있으므로 처리 할 함수를 직접 만드십시오.

def path_leaf(path):
    head, tail = ntpath.split(path)
    return tail or ntpath.basename(head)

확인:

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']
>>> [path_leaf(path) for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']


(1) 한 가지주의 사항이 있습니다. Linux 파일 이름 에는 백 슬래시가 포함될 수 있습니다 . 따라서 Linux에서는 r'a/b\c'항상 폴더 의 파일 b\c참조하고 aWindows에서는 항상 폴더의 하위 폴더에있는 c파일을 참조 합니다. 앞뒤 슬래시가 경로에 사용하는 경우 그래서, 당신은 필요 올바르게 해석 할 수 있도록 관련 플랫폼을 알고. 실제로는 백 슬래시가 Linux 파일 이름에서 거의 사용되지 않기 때문에 일반적으로 Windows 경로라고 가정하는 것이 안전하지만 코드를 작성할 때 실수로 보안 허점을 만들지 않도록 염두에 두십시오.ba


실제로 원하는 것을 정확하게 반환 하는 함수 가 있습니다.

import os
print(os.path.basename(your_path))

os.path.split 은 찾고있는 기능입니다.

head, tail = os.path.split("/tmp/d/a.dat")

>>> print(tail)
a.dat
>>> print(head)
/tmp/d

파이썬 3에서

>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'

import os
head, tail = os.path.split(p)
print tail

p는 입력 문자열이고 tail은 원하는 것입니다.

자세한 내용은 python os 모듈 문서참조하십시오.


귀하의 예에서 오른쪽에서 슬래시를 제거하여 반환해야합니다 c.

>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'

두 번째 수준 :

>>> os.path.filename(os.path.dirname(path))
'b'

업데이트 : lazyr정답을 제공 했다고 생각 합니다. 내 코드는 유닉스 시스템에서 Windows와 같은 경로에서 작동하지 않으며 Windows 시스템에서는 유닉스와 같은 경로에서 작동하지 않습니다.


fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]

이것은 다음을 반환합니다 : paint.exe

경로 또는 OS와 관련된 분할 기능의 sep 값을 변경하십시오.


이것은 표준 라이브러리와 함께 Linux 및 Windows에서도 작동합니다.

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

def path_leaf(path):
    return path.strip('/').strip('\\').split('/')[-1].split('\\')[-1]

[path_leaf(path) for path in paths]

결과 :

['c', 'c', 'c', 'c', 'c', 'c', 'c']

파일 경로가 "/"로 끝나지 않고 디렉토리가 "/"로 구분 된 경우 다음 코드를 사용하십시오. 우리가 일반적으로 알고 있듯이 경로는 "/"로 끝나지 않습니다.

import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))

But in some cases like URLs end with "/" then use the following code

import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))

but when your path sperated by "\" which you generally find in windows paths then you can use the following codes

import os
path_str = "c:\\var\www\index.html"
print(os.path.basename(path_str))

import os
path_str = "c:\\home\some_str\last_str\\"
split_path = path_str.rsplit("\\",1)
print(os.path.basename(split_path[0]))

You can combine both into one function by check OS type and return the result.


Here's a regex-only solution, which seems to work with any OS path on any OS.

No other module is needed, and no preprocessing is needed either :

import re

def extract_basename(path):
  """Extracts basename of a given path. Should Work with any OS Path on any OS"""
  basename = re.search(r'[^\\/]+(?=[\\/]?$)', path)
  if basename:
    return basename.group(0)


paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

print([extract_basename(path) for path in paths])
# ['c', 'c', 'c', 'c', 'c', 'c', 'c']


extra_paths = ['C:\\', 'alone', '/a/space in filename', 'C:\\multi\nline']

print([extract_basename(path) for path in extra_paths])
# ['C:', 'alone', 'space in filename', 'multi\nline']

Update:

If you only want a potential filename, if present (i.e., /a/b/ is a dir and so is c:\windows\), change the regex to: r'[^\\/]+(?![\\/])$' . For the "regex challenged," this changes the positive forward lookahead for some sort of slash to a negative forward lookahead, causing pathnames that end with said slash to return nothing instead of the last sub-directory in the pathname. Of course there is no guarantee that the potential filename actually refers to a file and for that os.path.is_dir() or os.path.is_file() would need to be employed.

This will match as follows:

/a/b/c/             # nothing, pathname ends with the dir 'c'
c:\windows\         # nothing, pathname ends with the dir 'windows'
c:hello.txt         # matches potential filename 'hello.txt'
~it_s_me/.bashrc    # matches potential filename '.bashrc'
c:\windows\system32 # matches potential filename 'system32', except
                    # that is obviously a dir. os.path.is_dir()
                    # should be used to tell us for sure

The regex can be tested here.


import os
file_location = '/srv/volume1/data/eds/eds_report.csv'
file_name = os.path.basename(file_location )  #eds_report.csv
location = os.path.dirname(file_location )    #/srv/volume1/data/eds

I have never seen double-backslashed paths, are they existing? The built-in feature of python module os fails for those. All others work, also the caveat given by you with os.path.normpath():

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c', 'a/./b/c', 'a\b/c']
for path in paths:
    os.path.basename(os.path.normpath(path))

The Windows separator can be in a Unix filename or Windows Path. The Unix separator can only exist in the Unix path. The presence of a Unix separator indicates a non-Windows path.

The following will strip (cut trailing separator) by the OS specific separator, then split and return the rightmost value. It's ugly, but simple based on the assumption above. If the assumption is incorrect, please update and I will update this response to match the more accurate conditions.

a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]

sample code:

b = ['a/b/c/','a/b/c','\\a\\b\\c','\\a\\b\\c\\','a\\b\\c','a/b/../../a/b/c/','a/b/../../a/b/c']

for a in b:

    print (a, a.rstrip("\\" if a.count("/") == 0 else '/').split("\\" if a.count("/") == 0 else '/')[-1])

Maybe just my all in one solution without important some new(regard the tempfile for creating temporary files :D )

import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1] 

Getting the values of abc.name will be a string like this: '/tmp/tmpks5oksk7' So I can replace the / with a space .replace("/", " ") and then call split(). That will return a list and I get the last element of the list with [-1]

No need to get any module imported.


For completeness sake, here is the pathlib solution for python 3.2+:

>>> from pathlib import PureWindowsPath

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...          'a/b/../../a/b/c/', 'a/b/../../a/b/c']

>>> [PureWindowsPath(path).name for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']

This works on both Windows and Linux.


In both Python 2 and 3, using the module pathlib2:

import posixpath  # to generate unix paths
from pathlib2 import PurePath, PureWindowsPath, PurePosixPath

def path2unix(path, nojoin=True, fromwinpath=False):
    """From a path given in any format, converts to posix path format
    fromwinpath=True forces the input path to be recognized as a Windows path (useful on Unix machines to unit test Windows paths)"""
    if not path:
        return path
    if fromwinpath:
        pathparts = list(PureWindowsPath(path).parts)
    else:
        pathparts = list(PurePath(path).parts)
    if nojoin:
        return pathparts
    else:
        return posixpath.join(*pathparts)

Usage:

In [9]: path2unix('lala/lolo/haha.dat')
Out[9]: ['lala', 'lolo', 'haha.dat']

In [10]: path2unix(r'C:\lala/lolo/haha.dat')
Out[10]: ['C:\\', 'lala', 'lolo', 'haha.dat']

In [11]: path2unix(r'C:\lala/lolo/haha.dat') # works even with malformatted cases mixing both Windows and Linux path separators
Out[11]: ['C:\\', 'lala', 'lolo', 'haha.dat']

With your testcase:

In [12]: testcase = paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
    ...: ...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']

In [14]: for t in testcase:
    ...:     print(path2unix(t)[-1])
    ...:
    ...:
c
c
c
c
c
c
c

The idea here is to convert all paths into the unified internal representation of pathlib2, with different decoders depending on the platform. Fortunately, pathlib2 includes a generic decoder called PurePath that should work on any path. In case this does not work, you can force the recognition of windows path using fromwinpath=True. This will split the input string into parts, the last one is the leaf you are looking for, hence the path2unix(t)[-1].

If the argument nojoin=False, the path will be joined back, so that the output is simply the input string converted to a Unix format, which can be useful to compare subpaths across platforms.

참고URL : https://stackoverflow.com/questions/8384737/extract-file-name-from-path-no-matter-what-the-os-path-format

반응형