用于从路径中提取基本文件名的正则表达式

时间:2014-09-02 20:06:36

标签: python regex

我想从一些文件路径中获取文件的字母部分。

files = ['data/Conversion/201406/MM_CLD_Conversion_Advertiser_96337_Daily_140606.zip', 
         'data/Match/201406/MM_CLD_Match_Advertiser_111423_Daily_140608.csv.zip', 
         'data/AQlog/201406/orx140605.csv.zip',
         'data/AQlog/201406/orx140605.csv.zip/']

目前我这样做:

  1. strip end slashes
  2. os.path.split()[1]获取文件名
  3. 两个os.path.splitext()删除可能的2个文件扩展名
  4. 丢失数字
  5. 丢失下划线
  6. 代码:

    for f in files:
        a = os.path.splitext(os.path.splitext(os.path.split(f.rstrip('/\\'))[1])[0])[0]
        b = re.sub('\d+', '', a).replace('_','')
    

    结果:

    'MMCLDConversionAdvertiserDaily'
    'MMCLDMatchAdvertiserDaily'
    'orx'
    'orx'
    

    使用编译的正则表达式函数是否有更快或更pythonic的方式?或者试图使用库os.path()非常合理?我也不必这样做超过100次,所以这不是速度问题,这只是为了清晰。

2 个答案:

答案 0 :(得分:2)

不使用正则表达式:

import os
import string
trans = string.maketrans('_', ' ')
def get_filename(path):
    # If you need to keep the directory, use os.path.split
    filename = os.path.basename(path.rstrip('/'))
    try:
        # If the extension starts at the last period, use
        # os.path.splitext
        # If the extension starts at the 2nd to last period,
        # use os.path.splitext twice
        # Continuing this pattern (since it sounds like you
        # don't know how many extensions a filename may have,
        # it may be safer to assume the file extension starts
        # at the first period. In which case, use
        # filename.split('.', 1).
        filename_without_ext, extension = filename.split('.', 1)
    except ValueError:
        filename_without_ext = filename
        extension = ''
    filename_cleaned = filename_without_ext.translate(trans, string.digits)
    return filename_cleaned

>>> path = 'data/Match/201406/MM_CLD_Match_Advertiser_111423_Daily_140608.csv.zip/'
>>> get_filename(path)
'MM CLD Match Advertiser  Daily '

做任何更可读的方法。如果问题不需要,我通常会避免使用正则表达式。在这种情况下,常规字符串操作可以执行您想要执行的所有操作。

如果要删除多余的空格(如结果中所示),请使用filename.replace(' ', '')。如果您可能有其他类型的空白,可以通过''.join(filename.split())

删除它

注意:如果您使用的是Python 3,请将trans=string.maketrans('_', ' ')替换为trans=str.maketrans('_', ' ', string.digits),将filename_without_ext.translate(trans, string.digits)替换为filename_without_ext.translate(trans)This change是改进unicode语言支持的一部分。查看更多:How come string.maketrans does not work in Python 3.1?

这是Python 3代码:

import os
import string
trans = string.maketrans('_', ' ', string,digits)
def get_filename(path):
    filename = os.path.basename(path.rstrip('/'))
    filename_without_ext = filename.split('.', 1)[0]
    filename_cleaned = filename_without_ext.translate(trans)
    return filename_cleaned

答案 1 :(得分:2)

您可以使用os.path中的相应功能来简化此操作。

首先,如果您致电normpath,则不再需要担心这两种路径分隔符,只需os.sep(请注意,如果您这样做,这是一个错误的事情)重新尝试,例如,在Linux上处理Windows路径......但如果您尝试在任何给定平台上处理本机路径,那么它正是您想要的)。它还会删除任何尾随斜杠。

接下来,如果您拨打basename而不是split,则无需再输入[1]个帖子。

不幸的是,basename没有splitsplitext相当......但是您可以轻松编写一个,这将使您的代码更具可读性,其方式与使用{ {1}}。

至于其余部分......正则表达式是删除任何数字的明显方法(尽管你真的不需要那里的basename)。而且,既然你已经有了一个正则表达式,那么将+放在那里而不是分开进行可能会更简单。

所以:

_

当然,如果你把它作为一个函数包装起来,整个事情可能会更具可读性:

def stripext(p):
    return os.path.splitext(p)[0]

for f in files:
    a = stripext(stripext(os.path.basename(os.path.normpath(f))))
    b = re.sub(r'[\d_]', '', a)

特别是因为您现在可以将循环转换为列表理解或生成器表达式或def process_path(p): a = stripext(stripext(os.path.basename(os.path.normpath(f)))) return re.sub(r'[\d_]', '', a) for f in files: b = process_path(f) 调用:

map

  

我只是对速度感到好奇,因为我的印象是编译的正则表达式函数非常快。

嗯,是的,总的来说。但是,未编译的字符串模式也非常快。

当您使用字符串模式而不是编译的regexp对象时,会发生以下情况:

  • processed_files = map(process_path, files) 模块在​​已编译正则表达式的缓存中查找模式。
  • 如果未找到,则编译字符串并将结果添加到缓存中。

因此,假设您在应用程序中不使用许多正则表达式,无论哪种方式,您的模式都只编译一次,并重复运行为编译表达式。使用未编译表达式的唯一额外成本是在缓存字典中查找它,这非常便宜 - 特别是当它是字符串文字时,所以它保证每次都是完全相同的字符串对象,因此它的哈希将被缓存为好吧,所以在第一次dict查找变成re和数组查找之后。

对于大多数应用程序,您可以假设mod缓存足够好,因此决定是否预编译正则表达式的主要原因是可读性。例如,当你有一个函数运行一系列复杂的正则表达式,其目的很难理解时,它肯定有助于为每个正则表达式命名,所以你可以写re ,在这种情况下,编译它们几乎是愚蠢的。