【问题标题】:Clean way to get the "true" stem of a Path object?获得 Path 对象的“真实”词干的干净方法?
【发布时间】:2015-10-31 15:25:47
【问题描述】:

预期的输入和输出:

a                 -> a
a.txt             -> a
archive.tar.gz    -> archive
directory/file    -> file
d.x.y.z/f.a.b.c   -> f
logs/date.log.txt -> date # Mine!

这是我觉得很脏的实现:

>>> from pathlib import Path
>>> example_path = Path("August 08 2015, 01'37'30.log.txt")
>>> example_path.stem
"August 08 2015, 01'37'30.log"
>>> example_path.suffixes
['.log', '.txt']
>>> suffixes_length = sum(map(len, example_path.suffixes))
>>> true_stem = example_path.name[:-suffixes_length]
>>> true_stem
"August 08 2015, 01'37'30"

因为它在没有后缀的Paths 上中断:

>>> ns_path = Path("no_suffix")
>>> sl = sum(map(len, ns_path.suffixes))
>>> ns_path.name[:-sl]
''

所以我需要先检查Path是否有后缀:

>>> def get_true_stem(path: Path):
...     if path.suffix:
...         sl = sum(map(len, path.suffixes))
...         return path.name[:-sl]
...     else:
...         return path.stem
...
>>>
>>> get_true_stem(example_path)
"August 08, 2015, 01'37'30"
>>> get_true_stem(ns_path)
"no_suffix"

这是我目前的用例:

>>> file_date = datetime.strptime(true_stem, "%B %d %Y, %H'%M'%S")
>>> file_date
datetime.datetime(2015, 8, 8, 1, 37, 30)
>>> new_dest = format(file_date, "%Y-%m-%dT%H:%M:%S%z") + ".log" # ISO-8601
>>> shutil.move(str(example_path), new_dest)

谢谢。

【问题讨论】:

  • 令人沮丧的是,Path 实际上知道这些后缀——它们存在于其suffixes 成员中。

标签: python path pathlib


【解决方案1】:

一个while循环方法怎么样,你一直使用.stem直到路径没有后缀,示例-

from pathlib import Path
example_path = Path("August 08 2015, 01'37'30.log.txt")
example_path_stem = example_path.stem
while example_path.suffixes:
    example_path_stem = example_path.stem
    example_path = Path(example_path_stem)

请注意,当example_path.suffixes 返回一个空列表时,while 循环退出循环(因为空列表在布尔上下文中为 False)。


示例/演示 -

>>> from pathlib import Path
>>> example_path = Path("August 08 2015, 01'37'30.log.txt")
>>> example_path_stem = example_path.stem
>>> while example_path.suffixes:
...     example_path_stem = example_path.stem
...     example_path = Path(example_path_stem)
...
>>> example_path_stem
"August 08 2015, 01'37'30"

第二个输入 - no_suffix -

>>> example_path = Path("no_suffix")
>>> example_path_stem = example_path.stem
>>> while example_path.suffixes:
...     example_path_stem = example_path.stem
...     example_path = Path(example_path_stem)
...
>>> example_path_stem
'no_suffix'

【讨论】:

    【解决方案2】:

    你可以.split它:

    >>> Path('logs/date.log.txt').stem.split('.')[0]
    'date'
    

    os.path 也可以:

    >>> os.path.basename('logs/date.log.txt').split('.')[0]
    'date'
    

    它通过了所有测试:

    In [11]: all(Path(k).stem.split('.')[0] == v for k, v in {
       ....:     'a': 'a',
       ....:     'a.txt': 'a',
       ....:     'archive.tar.gz': 'archive',
       ....:     'directory/file': 'file',
       ....:     'd.x.y.z/f.a.b.c': 'f',
       ....:     'logs/date.log.txt': 'date'
       ....: }.items())
    Out[11]: True
    

    【讨论】:

    • .partition 也可以使用,例如Path('logs/date.log.txt').stem.partition('.')[0]os.path.basename('logs/date.log.txt').partition('.')[0]。甚至可能是faster for some use cases
    • 请注意,这不适用于隐藏文件:Path('logs/.date.log.txt').stem.split('.')[0] == ''
    【解决方案3】:

    这是给定问题的另一种可能的解决方案:

    from pathlib import Path
    
    if __name__ == '__main__':
        dataset = [
            ('a', 'a'),
            ('a.txt', 'a'),
            ('archive.tar.gz', 'archive'),
            ('directory/file', 'file'),
            ('d.x.y.z/f.a.b.c', 'f'),
            ('logs/date.log.txt', 'date'),
        ]
        for path, stem in dataset:
            path = Path(path)
            assert path.name.replace("".join(path.suffixes), "") == stem
    

    【讨论】:

      【解决方案4】:

      如果你想唯一使用 pathlib,你也可以使用:

      >>> Path('logs/date.log.txt').with_suffix('').stem
      'date'
      

      编辑:

      正如 cmets 中所指出的,如果您的扩展名超过 2 个后缀,这将不起作用。虽然这听起来不太可能(并且 pathlib 本身没有处理它的本地方法),但如果您想唯一地使用 pathlib,您可以使用:

      >>> Path('logs/date.log.txt.foo').with_suffix('').with_suffix('').stem
      'date'
      

      【讨论】:

      • 如果有两个以上后缀则不起作用:Path('logs/date.log.txt.foo').with_suffix("").stem = 'date.log'
      • 你是对的。您必须添加另一个 .with_suffix("") 这可能会使其笨拙:` >>> Path('logs/date.log.txt.foo').with_suffix("").with_suffix("").stem 'date ' `
      【解决方案5】:

      另一种方法使用模式匹配:

      import re
      from pathlib import Path
      all(re.search('[.]|',Path(k).name) for k,v in {
         'a': 'a',
         'a.txt': 'a',
         'archive.tar.gz': 'archive',
         'directory/file': 'file',
         'd.x.y.z/f.a.b.c': 'f',
         'logs/date.log.txt': 'date'
         }.items())
      

      如果您的所有路径都至少有一个后缀,则可以使用模式“[.]”

      【讨论】:

        【解决方案6】:

        为什么不递归呢?

        from pathlib import Path
        
        def true_stem(path):
           stem = Path(path).stem
           return stem if stem == path else true_stem(stem)
        
        assert(true_stem('d.x.y.z/f.a.b.c') == 'f')
        

        【讨论】:

          猜你喜欢
          • 2014-01-15
          • 1970-01-01
          • 2010-09-16
          • 2019-09-27
          • 1970-01-01
          • 2017-12-22
          • 2011-09-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多