【问题标题】:Parsing filenames with python's re module使用 python 的 re 模块解析文件名
【发布时间】:2013-08-22 19:55:45
【问题描述】:

我正在开发视频播放器,它会扫描用户的视频文件并尝试从文件名中识别它们。如果视频是电影,我想得到它的名称和视频的质量,如果是电视节目,我想得到节目的名称、季节编号、剧集编号和视频质量。

我在谷歌上搜索了一些示例文件名并制作了简单的脚本来尝试获取信息,但是我很难处理异常情况,例如在质量之前有剧集名称,当文件具有像“PROPER”这样的标签时如果用户将视频的来源(如“BluRay”)放在质量之前。

如果有更熟练的正则表达式能提供一些帮助,我将不胜感激。

谢谢!

import re
names = [
    "The.Newsroom.2012.S02E06.720p.HDTV.x264-KILLERS.mkv",
    "Breaking.Bad.S05E10.Buried.HDTV.XviD-AFG.avi",
    "Breaking.Bad.S05E10.Buried.720p.HDTV.x264-AFG.mkv", #Incorrectly nonHD
    "Dexter.S08E08.HDTV.XviD-AFG.avi",
    "Dexter.S08E07.1080p.HDTV.x264-QCF.mkv",
    "Dexter S08E07 720p HDTV x264-QCF.mkv",
    "The.Great.Gatsby.2013.BluRay.1080p.DTS.x264-CHD.mkv", #Incorrectly nonHD
    "The Forbidden Girl 2013 BRRIP Xvid AC3-BHRG.avi",
    "Pain.&.Gain.2013.720p.BluRay.DD5.1.x264-HiDt.mkv",
    "Band.of.Brothers.S01E02.Day.of.Days.DVDRip.XviD-AC3-BAGS.avi",
    "Dexter.S08E06.PROPER.720p.HDTV.x264-IMMERSE.mkv", #Incorrectly nonHD
    "Dexter S08E06 PROPER 720p HDTV x264-IMMERSE.mkv" #Incorrectly nonHD
]
for name in names:
    tv = re.findall(r"(.*?)[ |.]S([\d+]{1,2})E([\d+]{1,2})[ |.]([\d+]{3,4}p|)", name) #FIXME: Get quality also after "PROPER/EPTITLE/.."
    if len(tv)>0:
        print("---------- TV ----------")
        print("Show: "+tv[0][0].replace(".", " "))
        print("Season: "+str(int(tv[0][1])))
        print("Episode: "+str(int(tv[0][2])))
        print("Quality: "+(tv[0][3] if len(tv[0][3])>0 else "nonHD"))
    else:
        movie = re.findall(r"(.*?[ |.][\d+]{4})[ |.]([\d+]{3,4}p|)", name) #FIXME: Get quality also after "BluRay/HDTV/HDDVD/.."
        if len(movie)>0:
            print("--------- MOVIE --------")
            print("Title: "+movie[0][0].replace(".", " "))
            print("Quality: "+(movie[0][1] if len(movie[0][1])>0 else "nonHD"))
        else:
            print("error")

【问题讨论】:

    标签: python regex parsing filenames


    【解决方案1】:

    正如 Josh 所提到的,+ 限定符不应与 {m,n} 一起使用。 + 匹配一个或多个 re 而 {m,n} 贪婪地匹配 m 到 n 个重复。 (参见:re syntax)。

    他还提出了一个很好的观点,即使用 re.VERBOSE 来帮助您的正则表达式的可读性。

    编辑:(感谢@eyguem 指出这一点)我可能错了,但您的[ |.] 是为了匹配空格和句号?如果是这样,您不需要| ,并且转义特殊字符(例如.)可能是一个好习惯。 (即[ \.])。

    如果您知道季节/剧集和质量之间的字符串是字母、空格或句点,您可以使用类似这样的内容(编辑:如果有非字母字符,如“-”、“+”等,您'需要将它们添加到字符集中):

        tv = re.findall(r"""(.*)          # Title
                            [ .]
                            S(\d{1,2})    # Season
                            E(\d{1,2})    # Episode
                            [ .a-zA-Z]*  # Space, period, or words like PROPER/Buried
                            (\d{3,4}p)?   # Quality
                        """, name, re.VERBOSE)
    

    同样,您可以对电影部分执行此操作:

    movie = re.findall(r"""(.*?[ .]\d{4})  # Title including year
                           [ .a-zA-Z]*     # Space, period, or words
                           (\d{3,4}p)?      # Quality
                        """, name, re.VERBOSE)
    

    这是输出:

    ---------- TV ----------
    Show: The Newsroom 2012
    Season: 2
    Episode: 6
    Quality: 720p
    ---------- TV ----------
    Show: Breaking Bad
    Season: 5
    Episode: 10
    Quality: nonHD
    ---------- TV ----------
    Show: Breaking Bad
    Season: 5
    Episode: 10
    Quality: 720p
    ---------- TV ----------
    Show: Dexter
    Season: 8
    Episode: 8
    Quality: nonHD
    ---------- TV ----------
    Show: Dexter
    Season: 8
    Episode: 7
    Quality: 1080p
    ---------- TV ----------
    Show: Dexter
    Season: 8
    Episode: 7
    Quality: 720p
    --------- MOVIE --------
    Title: The Great Gatsby 2013
    Quality: 1080p
    --------- MOVIE --------
    Title: The Forbidden Girl 2013
    Quality: nonHD
    --------- MOVIE --------
    Title: Pain & Gain 2013
    Quality: 720p
    ---------- TV ----------
    Show: Band of Brothers
    Season: 1
    Episode: 2
    Quality: nonHD
    ---------- TV ----------
    Show: Dexter
    Season: 8
    Episode: 6
    Quality: 720p
    ---------- TV ----------
    Show: Dexter
    Season: 8
    Episode: 6
    Quality: 720p
    

    【讨论】:

    • 你好。不需要转义括号之间的点:特殊字符放在括号之间时会失去其特殊性,这意味着一个位置的一组字符。所以[.G] 的意思是“一个点或字母 G”,而不是“任何字符或 G”
    • 对于"Breaking.Bad.S05E10.Hard-Buried.720p.HDTV.x264-AFG.mkv"(带有不在[ .a-zA-Z]中的-字符,结果将错误地为nonHD。也许是这样的情况或其他类似的事情永远不会发生......
    • 感谢您的感谢,但我认为没有兴趣将其写在您的回答中。 - 另外你不应该把所有句子都删掉,直到and it may be good habit to escape .... 的第一部分是完全正确的。
    【解决方案2】:

    如果您的正则表达式使用 re.VERBOSE 标志分解可能会有所帮助。

    我明白了

    [\d+]{3,4}
    

    我认为这是误导。这不是说“至少有一位小数重复三四次”吗?我觉得

    \d{3,4}
    

    没问题。

    在开发正则表达式时,我从创建小模式开始:

    episode_pattern = re.compile(r"S\d+E\d+", re.IGNORECASE)
    

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      [ae*6] 代表一个字符。这意味着这个字符可以是ae*6
      那么就没有必要写[ |.],顺便说一句,意思是“字符要么是,要么是|,要么是.”。

      我做了一些改进。如果您有任何问题,请随时问我。

      注意:像这样的部分:(?:[ .](\d{3}\d?p)|\Z).*? 之后 有必要强制惰性点 .*? 转到下一个点 .,如果有的话,然后是 720p,而不是在第一个点 处停止。 并考虑到数字和 p 是可选的。
      如果没有这样的 720p,惰性点会一直到字符串的末尾(\Z 强制它这样做)并声明它没有找到任何 720p .

      import re
      names = [
          "The.Newsroom.2012.S02E06.720p.HDTV.x264-KILLERS.mkv",
          "Breaking.Bad.S05E10.Buried.HDTV.XviD-AFG.avi",
          "Trekking.Bad.S05E12.Buried.720p.HDTV.x264-AFG.mkv",
          "Dexter.S08E08.HDTV.XviD-AFG.avi",
          "Dexter.S08E07.1080p.HDTV.x264-QCF.mkv",
          "Dexter S08E07 720p HDTV x264-QCF.mkv",
          "The.Great.Gatsby.2013.BluRay.1080p.DTS.x264-CHD.mkv",
          "The Forbidden Girl 2013 BRRIP Xvid AC3-BHRG.avi",
          "Pain.&.Gain.2013.720p.BluRay.DD5.1.x264-HiDt.mkv",
          "Band.of.Brothers.S01E02.Day.of.Days.DVDRip.XviD-AC3-BAGS.avi",
          "Dexter.S08E06.PROPER.720p.HDTV.x264-IMMERSE.mkv",
          "Dexter S08E06 PROPER 720p HDTV x264-IMMERSE.mkv"
          ]
      
      regtv = re.compile('(.+?)'
                         '[ .]S(\d\d?)E(\d\d?)'
                         '.*?'
                         '(?:[ .](\d{3}\d?p)|\Z)?')
      
      regmovie = re.compile('(.*?[ .]\d{4})'
                            '.*?'
                            '(?:[ .](\d{3}\d?p)|\Z)?')
      
      for name in names:
          tv = regtv.match(name)
          if tv:
              print("---------- TV ----------\n"
                    "Show: %s\n"
                    "Season: %s\n"
                    "Episode: %s\n"
                    "Quality: %s" %
                    (tv.group(1).replace(".", " "),
                     tv.group(2),
                     tv.group(3),
                     tv.group(4) if tv.group(4) else "nonHD")
                    )
          else:
              movie = regmovie.match(name)
              if movie:
                  print("--------- MOVIE --------\n"
                        "Title: %s\n"
                        "Quality: %s" %
                        (movie.group(1).replace(".", " "),
                         movie.group(2) if movie.group(2) else "nonHD")
                        )
              else:
                  print("----- error for -----\n%s" % name)
      

      【讨论】:

        【解决方案4】:

        我知道这个问题是用“re module”说的,但为了提供帮助而不是迂腐,这里有一个更简单、更快的文件名解析。

        file_name = path.rsplit('.', 1)[0].rsplit('/', 1)[-1]
        

        如果您需要它同时适用于 windows 和 unix,请在末尾添加 rsplit('\', 1)[-1]。这是快速、可预测的,并且每次都会解析文件名。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多