ti-enxame.com

Extrai o nome do arquivo do caminho, não importa o formato do os/path

Que biblioteca Python posso usar para extrair nomes de arquivos de caminhos, não importa qual seja o formato do sistema operacional ou do caminho?

Por exemplo, gostaria que todos esses caminhos me retornassem 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
515
Jerome

Usar os.path.split ou os.path.basename como os outros sugerem não funcionará em todos os casos: se você estiver executando o script no Linux e tentar processar um caminho clássico no estilo do Windows, ele falhará.

Os caminhos do Windows podem usar barra invertida ou barra como separador de caminho. Portanto, o módulo ntpath (que é equivalente a os.path quando executado no Windows) funcionará para todos(1) caminhos em todas as plataformas.

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

Obviamente, se o arquivo terminar com uma barra, o nome da base ficará vazio, então faça sua própria função para lidar com isso:

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

Verificação:

>>> 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) Há uma ressalva: nomes de arquivos Linux podem conter barras invertidas . Então, no linux, r'a/b\c' sempre se refere ao arquivo b\c na pasta a, enquanto no Windows, sempre se refere ao arquivo c na subpasta b da pasta a. Então, quando as barras para frente e para trás são usadas em um caminho, você precisa conhecer a plataforma associada para poder interpretá-la corretamente. Na prática, geralmente é seguro assumir que é um caminho para o Windows, já que as barras invertidas são raramente usadas em nomes de arquivos do Linux, mas lembre-se disso quando você codifica para não criar falhas acidentais na segurança.

561
Lauritz V. Thaulow

Na verdade, há um function que retorna exatamente o que você quer

print(os.path.basename(your_path))
864
stranac

os.path.split é a função que você está procurando

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

>>> print(tail)
a.dat
>>> print(head)
/tmp/d
166
Jakob Bowyer
import os
head, tail = os.path.split(p)
print tail

Suponha que p seja a string de entrada, tail é o que você quer.

Veja python os module docs para detalhes

32
number5

Em python 3

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

No seu exemplo, você também precisará remover a barra da direita do lado direito para retornar c:

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

Segundo nível:

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

update: acho que lazyr forneceu a resposta certa. Meu código não funcionará com caminhos semelhantes a janelas em sistemas unix e vice versus caminhos unix-like no sistema Windows.

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

isso retornará: Paint.exe

altere o valor sep da função split em relação ao seu caminho ou sistema operacional.

7
Eslam Hamouda

Isso está funcionando para Linux e Windows, bem como com biblioteca padrão

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]

Resultados:

['c', 'c', 'c', 'c', 'c', 'c', 'c']
7
Csabka

Eu nunca vi caminhos com dois caminhos invertidos, eles existem? O recurso interno do módulo python os falha para eles. Todos os outros trabalham, também a advertência dada por você com 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))
5
PythoNic

Aqui está uma solução somente de regex, que parece funcionar com qualquer caminho do sistema operacional em qualquer sistema operacional.

Nenhum outro módulo é necessário, e nenhum pré-processamento é necessário:

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']

O regex pode ser testado aqui .

3
Eric Duminil

O separador do Windows pode estar em um nome de arquivo Unix ou no Windows Path. O separador Unix só pode existir no caminho Unix. A presença de um separador Unix indica um caminho não-Windows.

O seguinte tira (separa o separador à direita) pelo separador específico do SO, depois divide e retorna o valor mais à direita. É feio, mas simples, baseado na suposição acima. Se a suposição estiver incorreta, atualize e atualizarei essa resposta para corresponder às condições mais precisas.

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

código de amostra:

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])
3
dusc2don

Talvez apenas o meu tudo em uma solução sem importante algum novo (considere o tempfile para criar arquivos temporários: D)

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

Obter os valores de abc.name será uma string como esta: '/tmp/tmpks5oksk7' Assim, posso substituir / por um espaço .replace("/", " ") e, em seguida, chamar split(). Isso retornará uma lista e eu recebo o Último elemento da lista com [-1]

Não há necessidade de obter qualquer módulo importado. 

cumprimentos

4k3nd0

2
Akendo

Para completar, aqui está a solução pathlib para o 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']

Isso funciona no Windows e no Linux.

1
Morgoth

Se o caminho do arquivo não terminar com "/" e os diretórios separados por "/", use o seguinte código. Como sabemos, geralmente o caminho não termina com "/".

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

Mas em alguns casos, como URLs, terminam com "/", use o seguinte código

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

mas quando seu caminho é procurado por "\", que você geralmente encontra em caminhos do Windows, então você pode usar os seguintes códigos

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]))

Você pode combinar ambos em uma função por tipo de sistema operacional e retornar o resultado.

1
Santosh kumar Manda

No Python 2 e 3, usando o módulo 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)

Uso:

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']

Com o seu 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

A ideia aqui é converter todos os caminhos na representação interna unificada de pathlib2, com diferentes decoders dependendo da plataforma. Felizmente, pathlib2 inclui um decodificador genérico chamado PurePath que deve funcionar em qualquer caminho. Caso isso não funcione, você pode forçar o reconhecimento do caminho do Windows usando fromwinpath=True. Isso dividirá a string de entrada em partes, a última é a folha que você está procurando, daí a path2unix(t)[-1].

Se o argumento nojoin=False, o caminho será unido de volta, de modo que a saída seja simplesmente a string de entrada convertida em um formato Unix, o que pode ser útil para comparar subcaminhos entre plataformas.

0
gaborous