多集文件名的正则表达式模式

时间:2014-06-22 01:43:13

标签: java regex

我正在尝试编写正则表达式,以便从文件名中获取有关电视节目集的数据。

我首先展示一些我正在处理的输入以及我喜欢数据输出的例子。

输入:

  • showname.s01e01e02e03.extension
  • showname.s01e01-02-03.extension

注意:剧集数量可能会有所不同,但至少会有2集。

输出:

  • 季节数,即' 01'来自s01
  • 剧集编号,即01e02e03或01-02-03

注意:如果可以使用正则表达式来获取个别剧集编号,那么这也很好 - 如果没有,我会将它们分开。 < / p>

我尝试过的事情:

not really that great with regular expressions,所以我目前的尝试可能很糟糕。无论如何,这是我到目前为止所得到的 - 显然不起作用:

(?i)s(?<season>\\d{1,4})(e(\\d{1,3})){2,}

我的想法是为季节编号创建一个组(该部分有效),然后尝试根据重复匹配剧集编号,但是,它在这里是3.41 AM,我可以&#39;真的把头包住了。

一个完整的解决方案会很好,但任何想法或指示都非常感激: - )

PS。如果接受的答案包含对正则表达式的解释,以便帮助我和他人学习,我会添加一笔赏金。

3 个答案:

答案 0 :(得分:1)

季节:01 - 集:01-02-03

底部的简单代码输出上面的字符串(如Java demo底部所示)。但是你说你想要一些解释,所以我们会一步一步地进行。

<强>一步步骤

让我们首先构建一个简单的正则表达式。然后我们会根据您的需求改进输出。

搜索: ^.*?s(\d{2})((?:e\d{2})+)\..*

替换: Season: $1 - Episodes: $2

输出: Season: 01 - Episodes: e01e02e03

regex101 demo中,请参阅底部的替换。在下面的Java代码中,我们不会替换任何东西。这只是为了看看事情是如何运作的。

解释匹配

  • ^声称我们位于字符串的开头
  • .*?懒惰地匹配字符,最多......
  • s(\d{2})匹配s,然后括号将两位数字捕获到第1组
  • ((?:e\d{2})+)中的外括号定义了捕获组2
  • 非捕获组(?:e\d{2})匹配e和两位数,
  • +量词确保我们这样做一次或多次,允许我们捕捉到第2组的所有剧集
  • \.与扩展名之前的时段匹配
  • .*匹配字符串的结尾

解释替换

  • 在下面的代码中,我们在剧集之间没有e
  • Season:写入文字字符Season:
  • $1是对第1组的反向引用,并插入季节
  • - Episodes:插入文字字符- Episodes:
  • $2是对第2组的反向引用,并插入剧集

更进一步:剧集编号(或其他改进)之间的破折号

让我们说你想要Season: 01 - Episodes: 01-02-03

这在简单的正则表达式搜索中是不可能的,并且在文本编辑器中替换,但在编程语言中很容易使用匹配的捕获组来构建输出字符串。

以下是示例Java代码(请参阅online demo底部的输出):

String subject = "showname.s01e01e02e03.extension";
Pattern regex = Pattern.compile("^.*?s(\\d{2})((?:e\\d{2})+).*");
Matcher m = regex.matcher(subject);
String myoutput = "No Match"; // initialize
if (m.find()) {
    myoutput = "Season: " + m.group(1) +" - Episodes: " ;
    myoutput += m.group(2).substring(1,m.group(2).length()).replace("e", "-");
}
System.out.println(myoutput); 

代码如何运作

  • 我们使用上面的正则表达式
  • 对于我们的匹配,我们分几步构建输出字符串
  • 在简单演示中,myoutput = "Season: " + m.group(1) +" - Episodes: " ;为我们提供了一些文字字符,第1组(季节)和更多文字字符
  • 对于剧集字符串,我们不是直接使用第2组(即m.group(2)),而是使用短划线替换所有e个字符:replace("e", "-") ...但仅在第一个字符串后面开始字符,因为我们不想用短划线替换第一个em.group(2).substring(1,m.group(2).length())

答案 1 :(得分:1)

(我和你一样生活在同一个时区,所以我的尝试可能也不准确,因为我半睡半醒但是我走了)

如果我理解正确(也试图分析你的正则表达式尝试)

  • 部分sXXXXeXXXeXXXsXXXXeXXX-XXX始终位于点之间
  • sXXXX只能存在一次,但可以有1-4位数字(此处由X表示),
  • 在季节信息之后必须有eXXX部分,并且在eXXX-XXX形式的元素之一(每个只能包含1-3个数字)。

在这种情况下,您可以使用正则表达式

[.]s(?<season>\\d{1,4})e(?<episodes>\\d{1,3}([e-]\\d{1,3})+)[.]

表示

  • [.] dot literal

  • s(?<season>\\d{1,4})将匹配sXXXX并将其存储在名为赛季的组中

  • 在季节信息之后放置
  • e字面意思(似乎是您的示例中必须的)

  • 在这种情况下,
  • (?<episodes>\\d{1,3}([e-]\\d{1,3})+)

    • \\d{1,3}将匹配XXX
    • ([e-]\\d{1,3})+以及此后eXXX-XXX中的至少一个。

    换句话说,它会匹配XXXeXXXXXX-XXX甚至是XXXeXXX-XXX之类的内容,并将其放入名为episodes

  • 的群组中 在搜索信息之后放置
  • [.]点文字

如果您想要一些具有分隔的剧集列表的结构,那么您只需要从名为episodes的组中拆分匹配。由于此匹配可以采用XXXeXXX-XXX格式,因此您可以分为e-,可以由正则表达式[e-]e|-表示。

演示:

String[] data = {
        "showname.s01e01e02e03.extension",
        "showname.s01e01-02-03.extension",
};
Pattern p = Pattern.compile(
                "[.]s(?<season>\\d{1,4})e(?<episodes>\\d{1,3}([e-]\\d{1,3})+)[.]",
                Pattern.CASE_INSENSITIVE);
for (String input : data){
    Matcher m = p.matcher(input);
    while (m.find()){
        String season = m.group("season");
        System.out.println(season);
        String episodes = m.group("episodes");
        System.out.println(m.group("episodes"));
        String[] singleEpisodes = episodes.split("[e-]");

        System.out.println("episode numbers"+Arrays.toString(singleEpisodes));
    }
    System.out.println("-----");
}

输出:

01
01e02e03
episode numbers[01, 02, 03]
-----
01
01-02-03
episode numbers[01, 02, 03]
-----

答案 2 :(得分:0)

也可以利用其他已经完成剧集名称的正则表达式匹配的人。例如,请参阅此页面,其中讨论了有关XBMC以及它与剧集名称匹配的一些高级主题:

http://wiki.xbmc.org/index.php?title=Advancedsettings.xml#tvshowmatching

如果链接在将来变得陈旧,提到的一些事情是:

<tvshowmatching>
  <regexp>[Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+)([^\\/]*)$</regexp>  <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
  <regexp>[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$</regexp>  <!-- foo.ep01, foo.EP_01 -->
  <regexp>([0-9]{4})[\.-]([0-9]{2})[\.-]([0-9]{2})</regexp>  <!-- foo.yyyy.mm.dd.* (byDate=true) -->
  <regexp>([0-9]{2})[\.-]([0-9]{2})[\.-]([0-9]{4})</regexp>  <!-- foo.mm.dd.yyyy.* (byDate=true) -->
  <regexp>[\\/\._ \[\(-]([0-9]+)x([0-9]+)([^\\/]*)$</regexp>  <!-- foo.1x09* or just /1x09* -->
  <regexp>[\\/\._ -]([0-9]+)([0-9][0-9])([\._ -][^\\/]*)$</regexp>  <!-- foo.103*, 103 foo -->
  <regexp>[\/._ -]p(?:ar)?t[_. -]()([ivx]+)([._ -][^\/]*)$</regexp>  <!-- Part I, Pt.VI -->
</tvshowmatching>

请注意,XBMC只是一个起点。我会查找所有相似类型的软件包,看看他们最终决定使用什么样的正则表达式,因为他们已经考虑了很多。