python - lenguaje - Extraiga el nombre del archivo de la ruta, sin importar el formato del sistema operativo/ruta
python tutorial (14)
Aquí hay una solución solo para expresiones regulares, que parece funcionar con cualquier ruta del sistema operativo en cualquier sistema operativo.
No se necesita ningún otro módulo, y tampoco se necesita preprocesamiento:
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'']
El regex puede ser probado here .
¿Qué biblioteca de Python puedo usar para extraer nombres de archivos de las rutas, sin importar cuál sea el sistema operativo o el formato de ruta?
Por ejemplo, me gustaría que todos estos caminos me devuelvan 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
El separador de Windows puede estar en un nombre de archivo Unix o ruta de Windows. El separador de Unix solo puede existir en la ruta de Unix. La presencia de un separador de Unix indica una ruta que no es de Windows.
Lo siguiente eliminará (corte el separador final) por el separador específico del sistema operativo, luego se dividirá y devolverá el valor más a la derecha. Es feo, pero simple basado en el supuesto anterior. Si la suposición es incorrecta, actualice y actualizaré esta respuesta para que coincida con las condiciones más precisas.
a.rstrip("////" if a.count("/") == 0 else ''/'').split("////" if a.count("/") == 0 else ''/'')[-1]
Código de muestra:
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])
El uso de os.path.split
o os.path.basename
como otros sugieren no funcionará en todos los casos: si está ejecutando el script en Linux e intenta procesar una ruta de estilo de Windows clásica, fallará.
Las rutas de Windows pueden usar barra diagonal invertida o barra inclinada como separador de ruta. Por lo tanto, el módulo ntpath
(que es equivalente a os.path cuando se ejecuta en Windows) funcionará para todas las (1) rutas en todas las plataformas.
import ntpath
ntpath.basename("a/b/c")
Por supuesto, si el archivo termina con una barra inclinada, el nombre base estará vacío, así que haga su propia función para resolverlo:
def path_leaf(path):
head, tail = ntpath.split(path)
return tail or ntpath.basename(head)
Verificación:
>>> 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) Hay una advertencia: los nombres de archivo de Linux pueden contener barras invertidas . Así que en linux, r''a/b/c''
siempre se refiere al archivo b/c
en la carpeta a, mientras que en Windows, siempre se refiere al archivo c
en la subcarpeta b
de la carpeta a. Por lo tanto, cuando se usan barras inclinadas hacia adelante y hacia atrás en una ruta, debe conocer la plataforma asociada para poder interpretarla correctamente. En la práctica, generalmente es seguro asumir que es una ruta de Windows, ya que las barras invertidas rara vez se usan en los nombres de archivo de Linux, pero tenga esto en cuenta cuando codifique para no crear agujeros de seguridad accidentales.
En python 3
>>> from pathlib import Path
>>> Path("/tmp/d/a.dat").name
''a.dat''
En realidad, hay una function que devuelve exactamente lo que quieres
print(os.path.basename(your_path))
En su ejemplo, también necesitará quitar la barra diagonal desde el lado derecho para devolver 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 nivel:
>>> os.path.filename(os.path.dirname(path))
''b''
actualización: creo que lazyr
ha proporcionado la respuesta correcta. Mi código no funcionará con rutas similares a Windows en sistemas Unix y viceversa con rutas similares a Unix en Windows.
Esto está funcionando para Linux y Windows también con la biblioteca estándar
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'']
Nunca he visto caminos de doble barra diagonal inversa, ¿existen? La característica incorporada del módulo de Python os
falla para esos. Todos los demás funcionan, también la advertencia que le da 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))
Para completar, aquí está la solución de pathlib
para 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'']
Esto funciona tanto en Windows como en Linux.
Tal vez solo mi solución todo en uno sin algunas novedades importantes (con respecto al archivo temporal para crear archivos temporales: D)
import tempfile
abc = tempfile.NamedTemporaryFile(dir=''/tmp/'')
abc.name
abc.name.replace("/", " ").split()[-1]
Obtener los valores de abc.name
será una cadena como esta: ''/tmp/tmpks5oksk7''
Así que puedo reemplazar /
con un espacio .replace("/", " ")
y luego llamar a split()
. Eso devolverá una lista y obtengo el último elemento de la lista con [-1]
No hay necesidad de importar ningún módulo.
atentamente
4k3nd0
os.path.split es la función que está buscando
head, tail = os.path.split("/tmp/d/a.dat")
>>> print(tail)
a.dat
>>> print(head)
/tmp/d
filename = path[path.rfind(''/'')+1:]
fname = str("C:/Windows/paint.exe").split(''//')[-1:][0]
esto devolverá: paint.exe
cambie el valor de sep de la función de división con respecto a su ruta o sistema operativo.
import os
head, tail = os.path.split(p)
print tail
Supongamos que p es la cadena de entrada, cola es lo que quieres.
Ver la os.path.split para más detalles.