【问题标题】:Regex pattern isn't matching certain show titles正则表达式模式与某些节目标题不匹配
【发布时间】:2015-08-05 07:56:35
【问题描述】:

使用 C# 正则表达式匹配并返回从字符串解析的数据会返回不可靠的结果。

我使用的模式如下:

Regex r=new Regex( 
      @"(.*?)S?(\d{1,2})E?(\d{1,2})(.*)|(.*?)S?(\d{1,2})E?(\d{1,2})",
      RegexOptions.IgnoreCase
);

以下是几个失败的测试用例


Ellen 2015.05.22 Joseph Gordon Levitt [REPOST]
The Soup 2015.05.22 [mp4]
Big Brother UK Live From The House (May 22, 2015)

应该返回

  • 显示名称(例如,Ellen
  • 日期(例如,2015.05.22
  • 额外信息(例如,Joseph Gordon Levitt [REPOST]

Alaskan Bush People S02 Wild Times Special

应该返回

  • 显示名称(例如,Alaskan Bush People
  • 季节(例如,02
  • 额外信息(例如,Wild Times Special

500 Questions S01E03

应该返回

  • 显示名称(例如,500 Questions
  • 季节(例如,01
  • 剧集(例如,03

有效并返回正确数据的示例

Boyster S01E13 – E14
Mysteries at the Museum S08E08
Mysteries at the National Parks S01E07 – E08
The Last Days Of… S01E06
Born Naughty? S01E02
Have I Got News For You S49E07

看起来,如果没有找到,模式会忽略 S 和 E,然后使用第一组匹配的数字来填充那个槽。

很明显,在这种模式上还需要做更多的工作来处理上述不同的字符串。非常感谢您在此问题上的帮助。

【问题讨论】:

  • @"(.*?)S?(\d{1,2})E?(\d{1,2})(.*)|(.*?)S?(\d{1,2})E?(\d{1,2})" 你为什么要写两次相同的模式?
  • 这不是同一个模式。请注意,任何尾随字符都以 (.*) 结尾,而另一个则没有。我发现如果我去掉 (.*),在剧集编号之后具有更多字符的字符串根本不会被捕获。
  • 我说的是第二部分是第一部分的子集,.* 匹配零个字符..??
  • 我想让您重新表述您的问题,因为您似乎正试图使用​​通配符和一个正则表达式来捕捉多种模式。我建议您展示一个正确的示例,说明您正在尝试正则表达式的输入,并且我还认为您需要有几种模式,并且可能需要多次解析文本,因为输入非常多样。
  • 避免使用 '.*' ,这将使整行结束。你需要更多或的来处理日期。使用组名称来处理空组。这是我的修复:@"(?'name'[^S]*)?S(?'season'\d{1,2})E?(?'episode'\d{1,2})?( ?'end'[^$]*)|(?'name'[^S]*)?S(?'season'\d{1,2})E(?'episode'\d{1,2} )"

标签: c# regex text-parsing


【解决方案1】:

分而治之

你试图用一个简单的表达式解析太多。这不会很好地工作。在这种情况下,最佳方法是将问题分成更小的问题,并分别解决每个问题。然后,我们可以稍后将所有内容组合成一个模式。

让我们为要提取的数据编写一些模式。

  • 季节/剧集:

    S\d+(?:E\d+(?:\s*\p{Pd}\s*E\d+)?)?
    

    我使用\p{Pd} 而不是- 来适应任何破折号类型。

  • 日期:

    \d{4}\.\d{1,2}\.\d{1,2}
    

    或者……

    (?i:January|February|March|April|May|June|July|August|September|October|November|December)
    \s*\d{1,2},\s*\d{4}
    
  • 写一个简单的模式以获得额外的信息:

    .*?
    

    (是的,这很笼统)

  • 我们也可以像这样检测节目格式:

    \[.*?\]
    
  • 您可以根据需要添加其他部件。

现在,我们可以将所有内容放在一个模式中,使用组名来提取数据:

^\s*
(?<name>.*?)
(?<info> \s+ (?:
    (?<episode>S\d+(?:E\d+(?:\s*\p{Pd}\s*E\d+)?)?)
    |
    (?<date>\d{4}\.\d{1,2}\.\d{1,2})
    |
    \(?(?<date>(?i:January|February|March|April|May|June|July|August|September|October|November|December)\s*\d{1,2},\s*\d{4})\)?
    |
    \[(?<format>.*?)\]
    |
    (?<extra>(?(info)|(?!)).*?)
))*
\s*$

只需忽略info 组(它用于extra 中的条件,因此extra 不会消耗应该是节目名称的一部分)。而且您可以获得多个 extra 信息,因此只需将它们连接起来,在每个部分之间放置一个空格。

示例代码:

var inputData = new[]
{
    "Boyster S01E13 – E14",
    "Mysteries at the Museum S08E08",
    "Mysteries at the National Parks S01E07 – E08",
    "The Last Days Of… S01E06",
    "Born Naughty? S01E02",
    "Have I Got News For You S49E07",
    "Ellen 2015.05.22 Joseph Gordon Levitt [REPOST]",
    "The Soup 2015.05.22 [mp4]",
    "Big Brother UK Live From The House (May 22, 2015)",
    "Alaskan Bush People S02 Wild Times Special",
    "500 Questions S01E03"
};

var re = new Regex(@"
    ^\s*
    (?<name>.*?)
    (?<info> \s+ (?:
        (?<episode>S\d+(?:E\d+(?:\s*\p{Pd}\s*E\d+)?)?)
        |
        (?<date>\d{4}\.\d{1,2}\.\d{1,2})
        |
        \(?(?<date>(?i:January|February|March|April|May|June|July|August|September|October|November|December)\s*\d{1,2},\s*\d{4})\)?
        |
        \[(?<format>.*?)\]
        |
        (?<extra>(?(info)|(?!)).*?)
    ))*
    \s*$
", RegexOptions.IgnorePatternWhitespace);

foreach (var input in inputData)
{
    Console.WriteLine();
    Console.WriteLine("--- {0} ---", input);

    var match = re.Match(input);
    if (!match.Success)
    {
        Console.WriteLine("FAIL");
        continue;
    }

    foreach (var groupName in re.GetGroupNames())
    {
        if (groupName == "0" || groupName == "info")
            continue;

        var group = match.Groups[groupName];
        if (!group.Success)
            continue;

        foreach (Capture capture in group.Captures)
            Console.WriteLine("{0}: '{1}'", groupName, capture.Value);
    }
}

这个的输出是......

--- Boyster S01E13 - E14 ---
name: 'Boyster'
episode: 'S01E13 - E14'

--- Mysteries at the Museum S08E08 ---
name: 'Mysteries at the Museum'
episode: 'S08E08'

--- Mysteries at the National Parks S01E07 - E08 ---
name: 'Mysteries at the National Parks'
episode: 'S01E07 - E08'

--- The Last Days Ofâ?¦ S01E06 ---
name: 'The Last Days Ofâ?¦'
episode: 'S01E06'

--- Born Naughty? S01E02 ---
name: 'Born Naughty?'
episode: 'S01E02'

--- Have I Got News For You S49E07 ---
name: 'Have I Got News For You'
episode: 'S49E07'

--- Ellen 2015.05.22 Joseph Gordon Levitt [REPOST] ---
name: 'Ellen'
date: '2015.05.22'
format: 'REPOST'
extra: 'Joseph'
extra: 'Gordon'
extra: 'Levitt'

--- The Soup 2015.05.22 [mp4] ---
name: 'The Soup'
date: '2015.05.22'
format: 'mp4'

--- Big Brother UK Live From The House (May 22, 2015) ---
name: 'Big Brother UK Live From The House'
date: 'May 22, 2015'

--- Alaskan Bush People S02 Wild Times Special ---
name: 'Alaskan Bush People'
episode: 'S02'
extra: 'Wild'
extra: 'Times'
extra: 'Special'

--- 500 Questions S01E03 ---
name: '500 Questions'
episode: 'S01E03'

【讨论】:

  • 将对此进行测试。泰。
  • 您根据问题中的上述信息返回了我需要的内容。我确实遇到了另一个也许你可以解决的问题(它会帮助我更好地理解分组)>>Jimmy Fallon 2015 05 22 Sting and Kevin Connolly。我试图为这个日期添加一个选项,但不确定:)
  • 当然,您可以添加:(?&lt;date&gt;\d{4}[ ]\d{1,2}[ ]\d{1,2})(?&lt;date&gt;\d{4}\s\d{1,2}\s\d{1,2}),或者甚至将 (?&lt;date&gt;\d{4}\.\d{1,2}\.\d{1,2}) 更改为 (?&lt;date&gt;\d{4}[. ]\d{1,2}[. ]\d{1,2}),但最后一个选项也可以接受 2015 05.22 - 您选择最佳变体.
【解决方案2】:

试试这个:

(?<name>.*?)(?:S(?<season>\d{1,2}))?(?:E(?<episode>\d{1,2}))?(?<date>\d{4}\.\d{2}\.\d{2})(?<extra>.*)?

【讨论】:

  • 会试一试。泰。
  • 这个方法没有返回正确的结果。感谢您的尝试;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-19
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多