【问题标题】:Cleanest way to parse this pattern of strings?解析这种字符串模式的最简洁方法?
【发布时间】:2009-07-28 20:05:37
【问题描述】:

我的音乐文件名如下:

Gorillaz (2001)
Gorillaz (7th State Mix) (2002)
Gorillaz (2001) (Featuring Travis)
Gorillaz (1Mix) (2003)
Gorillaz (1000) (2001)

如何以最简洁、最简单的方式解析年份?

现在我通过查找每个'(' 来解析它们,然后确保()s 之间的字符数为4,第一个字符为1 或2,并且可以使用TryParse 解析它们?

我可以使用单个正则表达式解析这些类型的字符串吗?


编辑:

年份最多为 50-60 岁,因此不超过 1950 年。

【问题讨论】:

  • 你一定要像那样解析文件名吗?是否有可以用来存储这些信息的数据结构?
  • 这里有更多测试用例供您参考:Prince Remix (1999) (1999) 2001 Soundtrack (2001) (1974)
  • @Brian,是的,我为此使用了一个数据结构,然后我需要通过这一年。
  • 您的第一个问题是听 Gorillaz。 </obligatory>

标签: c# .net regex string parsing


【解决方案1】:

我认为这可以满足您的需求:

using System;
using System.Text.RegularExpressions;

class Test
{
    static void Main()
    {
        string[] samples = new[] { "Gorillaz (2001)",
                "Gorillaz (7th State Mix) (2002)",
                "Gorillaz (2001) (Featuring Travis)",
                "Two matches: (2002) (1950)",
                "Gorillaz (1Mix) (1952)",
                "Gorillaz (1Mix) (2003)",
                "Gorillaz (1000) (2001)" };

        foreach (string name in samples)
        {
            ShowMatches(name);
        }
    }

    static readonly Regex YearRegex = new Regex(@"\((19[5-9]\d|200\d)\)");

    static void ShowMatches(string name)
    {
        Console.WriteLine("Matches for: {0}", name);
        foreach (Match match in YearRegex.Matches(name))
        {
            Console.WriteLine(match.Value);
        }
    }
}

这将在 2009 年有效。要使其超出此范围,请使用 @"((19[5-9]\d|20[01]\d))" 等。

请注意,这仍然会打印出括号 - 您可以使用组构造来摆脱它们,但我个人只会使用 Substring :)

【讨论】:

  • 可能想要制作 2\d{3} —— 那么在接下来的一千年里你就不需要重写它了。
  • 不,这是故意这样 - 这样它就不会误分类 2500(这显然 不是 一年)。
  • (诚然,当你做到 20[01]\d 时,它仍然会假设 2019 年只是 2010 年,但是嘿......)
  • 谢谢乔恩,你知道我需要覆盖什么,说 149 年吗?所以从 1950 年到 2099 年?我可以为此想出一个正则表达式吗?
  • 你可以使用它,或者只是在末尾使用 \d\d​​ 来匹配两个数字(或者实际上是 \d{2})。
【解决方案2】:

此正则表达式将匹配您的模式:

@"\(([12]\d{3})\)"

然后您可以提取第 1 组以获取年份。然后,您可以使用Convert.ToInt32 将年份作为int,并检查它是否大于 1950(最好将其作为数字比较而不是使正则表达式过于复杂)。

【讨论】:

    【解决方案3】:

    您应该能够使用正则表达式来匹配它。 以下是您可以尝试使用的模式:

    \([12][0-9]{3}\)
    

    不要忘记启用贪婪。这也将匹配最后一行的 (1000)。这也需要吗?

    编辑:

     \((19|20)[0-9]{2}\)
    

    如果您不希望 (1000) 作为匹配项,将完成这项工作

    问候

    【讨论】:

    • 我认为它不应该与最后一行中的 (1000) 匹配,因为年份不会早于 1950 年。
    • 它与 1000 不匹配,对。好吧... 1000 is 实际上早于 1950 ;) 但是是的,这不是它不匹配的原因。无论如何,乔恩在他的代码中的模式看起来更好:P
    【解决方案4】:

    考虑到你有一些看起来像几年但不是的东西,例如(1000) 如果您认为您的程序会存在一段时间,我会寻找 19**、20** 和 21** :)

    /\(19\d\d|20\d\d|21\d\d\)/
    

    对于您的输入,这给出:

    2001
    2002
    2001
    2003
    2001
    2001
    

    【讨论】:

      【解决方案5】:

      看起来很棘手,除非我们更多地了解其中一些括号的用途:如果您的“(1000)”不是真正的一年,您可能有一个“(2000)”也不是真正的一年.我说的是示例中的最后一行:

      大猩猩 (1000) (2001)

      如果这是有效的,为什么不这样呢? :

      大猩猩 (2000) (2001)

      后一个示例中的 (2000) 与前一个示例中的 (1000) 具有相同的概念角色(不是一年)。您的正则表达式如何知道哪一年?如果你知道这不会发生,如何你现在不会发生?

      【讨论】:

      • 他说音乐不超过 60 年。
      • 谢谢乔尔。你说 2000 年不是一年是什么意思?
      • 我明白了。这一年只会从 1950 年开始。如果有 2 个有效年份可能,那么只会使用第一个。我会记录下来,所以如果用户有这样的文件,那么他有责任确保他们只有 1 年。
      • 我认为你还没有完全掌握它。我说的是一个单独的属性,它根本不是一年,但在 1950 年到 2050 年之间偶尔会出现 4 个数字。
      • 我明白了。但是你的意思是像这样的值,但也在括号内?这不是不太可能吗? :)
      猜你喜欢
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      • 2016-06-22
      • 2019-04-07
      • 2010-09-27
      • 1970-01-01
      • 2014-01-23
      • 1970-01-01
      相关资源
      最近更新 更多