【问题标题】:Regular expression match last occurence of year in string正则表达式匹配字符串中最后一次出现的年份
【发布时间】:2018-06-14 02:34:51
【问题描述】:

我编写了一个带有以下函数的 python 脚本,该函数将包含多个日期的文件名作为输入。

代码

import re
from datetime import datetime

def ExtractReleaseYear(title):
    rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
    match = rg.search(title) # Using non-greedy match on filler
    if match:
        releaseYear = match.group(1)
        try:
            if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
                return releaseYear
        except ValueError:
            print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
            return ""

print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))

输出

返回:2012 -- 我希望这是 2009 年(即字符串中最后一次出现的年份)

返回:2012 -- 这是正确的! (年份的最后出现是第一个,因此正确)

返回:2001 -- 我希望这是 1968 年(即字符串中最后一次出现的年份)

问题

可以看出,正则表达式将只针对一年的第一次出现而不是最后一次出现。这是有问题的,因为某些标题(例如此处包含的标题)以年份开头。

在寻找获得今年最后一次出现的方法后,我找到了 negative lookahead、last occurrence of repeated group 和 last 4 digits in URL 等资源,但这些资源都没有让我更接近于实现预期的结果。目前没有任何问题可以回答这个独特的案例。

预期结果

  • 我想从给定的文件名中提取一年的最后一次出现(而不是第一次出现),并使用上面输出引用中所述的现有定义/函数返回它。 虽然我使用过在线正则表达式引用,但我是正则表达式的新手,希望有人向我展示如何实现此过滤器以处理上述文件名。干杯,伙计们。

【问题讨论】:

  • 因为你总是在检查 group(1) 它给你第一个匹配。检查组长度,如果超过一个,取最后一组的匹配值。
  • 没有真正的解决方案可以做到这一点,特别是因为文件名可以有多种形式,例如,所有文件名在“1080”之后总是有一个“p”的可能性很小。跨度>
  • @ProGrammer:如果电影标题包含年份并且文件名中缺少发行年份怎么办?此外,您应该选择 1895 年(Louis 和 Auguste Lumière 的 sortie d'usine 发行年份),而不是 1900 年。
  • ...或 1888 年用于 Louis Le Prince 电影。
  • @CasimiretHippolyte 我已将下边界的范围扩展到1888。假设通过函数运行标题2018.3D.1080p.BRRip.SBS.x264.AAC,它返回2018(注意电影标题包含年份并且文件名中缺少发行年份)。在这种情况下,最后一次出现也是第一次出现。如果最后一次出现是某种上传/记录日期,例如2018.3D.1080p.BRRip.SBS.x264.AAC.01-01-2018 我很想看到一种过滤掉此类实例的聪明方法。目前,我相信这是电影片名中罕见的格式。

标签: python regex string date filenames


【解决方案1】:

根据@kenyanke 的回答,选择findall() 而不是search() 将是一个更好的选择,因为前者返回所有不重叠的匹配模式。您可以选择最后一个匹配模式为releaseYear。这是我的正则表达式来查找releaseYear

rg = re.compile(r'[^a-z](\d{4})[^a-z]', re.IGNORECASE)
match = rg.findall(title)
if match:
        releaseYear = match[-1]

上面的正则表达式假设releaseYear之前或之后的直接字母是非字母字符。三个字符串的结果(match)是

['2009']
['2012']
['1968']

【讨论】:

    【解决方案2】:

    考虑使用 findall() 而不是 search()?

    它会将找到的所有值从左到右放入一个列表中,只需访问最右边的值即可获得所需的值。

    import re
    from datetime import datetime
    
    def ExtractReleaseYear(title):
        rg = re.compile('.*?([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
        match = rg.findall(title)
    
        if match:
            try:
                releaseYear = match[-1][-1]
                if int(releaseYear) >= 1900 and int(releaseYear) <= int(datetime.now().year) and int(releaseYear) <= 2099: # Film between 1900-2099
                    return releaseYear
            except ValueError:
                print("ERROR: The film year in the file name could not be converted to an integer for comparison.")
                return ""
    
    print(ExtractReleaseYear('2012.(2009).3D.1080p.BRRip.SBS.x264'))
    print(ExtractReleaseYear('Into.The.Storm.2012.1080p.WEB-DL.AAC2.0.H264'))
    print(ExtractReleaseYear('2001.A.Space.Odyssey.1968.1080p.WEB-DL.AAC2.0.H264'))
    

    【讨论】:

      【解决方案3】:

      有两点你需要改变:

      1. 第一个 .*? 惰性模式必须转换为贪婪 .*(在这种情况下,.* 之后的子模式将匹配字符串中的最后一次出现)
      2. 您需要使用的组是组 2,而不是组 1(因为它是存储年份数据的组)。或者使第一个捕获组不捕获。

      见this demo:

      rg = re.compile('.*([\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
      ...
      releaseYear = match.group(2)
      

      或者:

      rg = re.compile('.*(?:[\[\(]?((?:19[0-9]|20[01])[0-9])[\]\)]?)', re.IGNORECASE|re.DOTALL)
      ...
      releaseYear = match.group(1)
      

      【讨论】:

        猜你喜欢
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多