如何获取到特定子目录的路径?
How to get the path up to a specific sub-directory?
我想要达到的目标
给定一条路径,我需要提取路径中特定命名的子目录(如果存在)之前的部分 - 我们将其称为 stopper 以轻松实现在这个问题中识别它。
需要注意的是路径可能以stopper
开始或结束
input/output的一些样本对:
path = 'some/path/to/my/file.ext'
# ends with stopper
stopper = 'my'
result = 'some/path/to'
# begins with stopper
stopper = 'some'
result = ''
# stopper in middle
stopper = 'to'
result = 'some/path'
# special case - should stop at first stopper location
path = 'path/to/to/my/file.ext'
stopper = 'to'
result = 'path'
到目前为止我有什么
我设计了两种这样的方法来获得答案:
正则表达式
import re
# p = path; s = stopper
def regex_method(p,s):
regex = r"(?:(?!(?:^|(?<=/))" + s + r").)+(?=/)"
m = re.match(regex, p)
if m:
return m.group()
return ''
这可行,但根据传递的 stopper 值容易失败 - 不适合在生产中使用。
OS
import os
# p = path; s = stopper
def os_method(p,s):
parts = os.path.dirname(p).split('/')
return '/'.join(parts[:parts.index(s)])
这似乎比正则表达式更简洁,但我觉得我需要拆分字符串,然后根据值的索引列出列表,然后将它们连接在一起,这对我来说似乎很奇怪。我觉得这可以简化或改进。
我的问题
- 是否有更惯用的方式来拆分特定目录名称的路径?
- 是否有使用列表推导实现此目的的简单方法?
另一种看似更有效且更简单的方法是使用 itertools.takewhile
,它(来自文档)创建一个迭代器,只要谓词为真,它就会从可迭代对象中获取 returns 个元素:
import os
from itertools import takewhile
def it_method(p, s):
return '/'.join(takewhile(lambda d : d != s, p.split('/')))
测试:
print(it_method('some/path/to/my/file.ext', 'my'))
print(it_method('some/path/to/my/file.ext', 'to'))
print(it_method('some/path/to/my/file.ext', 'some'))
print(it_method('some/path/to/to/my/file.ext', 'to'))
输出:
some/path/to
some/path
some/path
所以在这种情况下,它会一直生成目录名称,直到遇到 stopper
。
谓词也可以缩短为 s.__ne__
而不是使用 lambda
函数:
def it_method(p,s):
return '/'.join(takewhile(s.__ne__, p.split('/')))
您可以像这样在生成器上使用 pathlib
模块和 next
:
from pathlib import Path
# p = path; s = stopper
def get_path(p,s):
return next((parent for parent in Path(p).parents if not any(x in str(parent) for x in (f'/{s}/', f'{s}/', f'/{s}')) and str(parent) != s), '')
path = 'some/path/to/my/file.ext'
# ends with stopper
stopper = 'to'
print(get_path(path, stopper))
# some/path
我建议使用 pathlib
:
def split_path(path, stopper):
parts = path.parts
idx = next((idx for idx, part in enumerate(parts) if part == stopper))
result = Path(*parts[:idx])
return result
使用您的示例:
path = Path('some/path/to/my/file.ext'
)
stopper = 'my'
split_path(path, stopper)
输出:PosixPath('some/path/to')
stopper = 'some'
split_path(path, stopper)
输出:PosixPath('.')
stopper = 'to'
split_path(path, stopper)
输出:PosixPath('some/path')
我想要达到的目标
给定一条路径,我需要提取路径中特定命名的子目录(如果存在)之前的部分 - 我们将其称为 stopper 以轻松实现在这个问题中识别它。
需要注意的是路径可能以stopper
开始或结束input/output的一些样本对:
path = 'some/path/to/my/file.ext'
# ends with stopper
stopper = 'my'
result = 'some/path/to'
# begins with stopper
stopper = 'some'
result = ''
# stopper in middle
stopper = 'to'
result = 'some/path'
# special case - should stop at first stopper location
path = 'path/to/to/my/file.ext'
stopper = 'to'
result = 'path'
到目前为止我有什么
我设计了两种这样的方法来获得答案:
正则表达式
import re
# p = path; s = stopper
def regex_method(p,s):
regex = r"(?:(?!(?:^|(?<=/))" + s + r").)+(?=/)"
m = re.match(regex, p)
if m:
return m.group()
return ''
这可行,但根据传递的 stopper 值容易失败 - 不适合在生产中使用。
OS
import os
# p = path; s = stopper
def os_method(p,s):
parts = os.path.dirname(p).split('/')
return '/'.join(parts[:parts.index(s)])
这似乎比正则表达式更简洁,但我觉得我需要拆分字符串,然后根据值的索引列出列表,然后将它们连接在一起,这对我来说似乎很奇怪。我觉得这可以简化或改进。
我的问题
- 是否有更惯用的方式来拆分特定目录名称的路径?
- 是否有使用列表推导实现此目的的简单方法?
另一种看似更有效且更简单的方法是使用 itertools.takewhile
,它(来自文档)创建一个迭代器,只要谓词为真,它就会从可迭代对象中获取 returns 个元素:
import os
from itertools import takewhile
def it_method(p, s):
return '/'.join(takewhile(lambda d : d != s, p.split('/')))
测试:
print(it_method('some/path/to/my/file.ext', 'my'))
print(it_method('some/path/to/my/file.ext', 'to'))
print(it_method('some/path/to/my/file.ext', 'some'))
print(it_method('some/path/to/to/my/file.ext', 'to'))
输出:
some/path/to
some/path
some/path
所以在这种情况下,它会一直生成目录名称,直到遇到 stopper
。
谓词也可以缩短为 s.__ne__
而不是使用 lambda
函数:
def it_method(p,s):
return '/'.join(takewhile(s.__ne__, p.split('/')))
您可以像这样在生成器上使用 pathlib
模块和 next
:
from pathlib import Path
# p = path; s = stopper
def get_path(p,s):
return next((parent for parent in Path(p).parents if not any(x in str(parent) for x in (f'/{s}/', f'{s}/', f'/{s}')) and str(parent) != s), '')
path = 'some/path/to/my/file.ext'
# ends with stopper
stopper = 'to'
print(get_path(path, stopper))
# some/path
我建议使用 pathlib
:
def split_path(path, stopper):
parts = path.parts
idx = next((idx for idx, part in enumerate(parts) if part == stopper))
result = Path(*parts[:idx])
return result
使用您的示例:
path = Path('some/path/to/my/file.ext'
)
stopper = 'my'
split_path(path, stopper)
输出:PosixPath('some/path/to')
stopper = 'some'
split_path(path, stopper)
输出:PosixPath('.')
stopper = 'to'
split_path(path, stopper)
输出:PosixPath('some/path')