c#:regex如何区分字符串的两种变体

本文关键字:两种 字符串 regex 何区 | 更新日期: 2023-09-27 17:56:11

这很难解释到足以提出问题,但我会尝试:

我有两种用户输入的可能性:

S01E05或0105(两个不同的输入字符串(

它们都被翻译成第01季第05集

但如果他们的用户向后输入E05S01或0501,我需要能够返回相同的结果,第一季第05集

对此的控制是用户定义原始文件名的格式,如下所示:"SssEee"--大写字母"S"表示以下小写字母"S"属于Season,大写字母"E"表示以下大写字母"E"属于Episode。因此,如果用户决定将格式定义为EeeSS,那么我的函数仍然应该返回相同的结果,因为它知道哪些数字属于季节或剧集。

我还没有什么工作要分享,但我正在玩的是一个构建regex模式的循环。到目前为止,该函数接受用户格式和文件名:

public static int(string userFormat, string fileName)
{
}

userFormat应该是一个字符串,看起来像这样:

t.t.t.Ssee

甚至

t.Ssee

其中t代表标题,其余的你都知道。

文件名可能如下所示:

战列舰.银河.S01E05.mkv

我得到了一个函数,通过使用userFormat构建正则表达式字符串,从文件名中提取标题

public static string GetTitle(string userFormat, string fileName)
        {
            string pattern = "^";
            char positionChar;
            string fileTitle;
            for (short i = 0; i < userFormat.Length; i++)
            {
                positionChar = userFormat[i];
                //build the regex pattern
                if (positionChar == 't')
                {
                    pattern += @"'w+";
                }
                else if (positionChar == '#')
                {
                    pattern += @"'d+";
                }
                else if (positionChar == ' ')
                {
                    pattern += @"'s+";
                }
                else
                    pattern += positionChar;
            }
            //pulls out the title with or without the delimiter
            Match title = Regex.Match(fileName, pattern, RegexOptions.IgnoreCase);
            fileTitle = title.Groups[0].Value;
            //remove the delimiter
            string[] tempString = fileTitle.Split(@"'/.-<>".ToCharArray());
            fileTitle = "";
            foreach (string part in tempString)
            {
                fileTitle += part + " ";
            }
            return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fileTitle);
        }

但我有点纠结于如何提取剧集和季号。在我的脑海中,我认为这个过程看起来像:

  • 通过userFormat字符串查找大写的S
  • 确定大写字母s后面有多少小写字母"s">
  • 构建描述以下内容的正则表达式
  • 搜索文件名并找到该模式
  • 从该模式中提取数字

听起来很简单,但我很难把它付诸行动。复杂的是文件名中的格式可能是S01E05,也可能只是0105。当用户定义格式时,这两种情况都将由用户识别。

Ex 1。文件名为战列星.卡拉狄加.S01E05

提交的用户格式将是t.t。?ss?ee

Ex 2。文件名为战列星.卡拉狄加.0105

提交的用户格式将是t.t.Sssee

Ex 3。文件名为战列星.卡拉狄加.0501

提交的用户格式将是t.t.EeeSS

对不起这本书。。。概念很简单,regex函数应该是动态的,允许用户定义文件名的格式,我的方法可以在其中生成表达式,并使用它从文件名中提取信息。有东西告诉我,这比看起来更简单。。。但是我不知所措。哈哈…有什么建议吗?

c#:regex如何区分字符串的两种变体

所以如果我读对了,你就知道季节/剧集编号在字符串中的位置,因为用户已经告诉你了。也就是说,您有t.t.<number>.more.stuff<number>可以采取以下形式之一:

SssEee
EeeSss
ssee
eess

或者你说用户可以定义季节和剧集将使用多少数字?也就是说,它可能是S01E123吗?

我不确定你是否需要正则表达式。既然你知道格式,而且似乎东西是用句点分隔的(我假设在各个字段中不可能有句点(,你应该能够使用String.Split来提取片段,并且你从用户的格式中知道季节/剧集在结果数组中的位置。现在有一个字符串,它采用上面的一种形式。

您有用户的格式定义和季节/剧集编号。您应该能够编写一个循环,将两个字符串一起遍历并提取必要的信息,或者发出错误。

string UserFormat = "SssEee";
string EpisodeNumber = "0105";
int ifmt = 0;
int iepi = 0;
int season = 0;
int episode = 0;
while (ifmt <= UserFormat.Length && iepi < EpisodeNumber.Length)
{
    if ((UserFormat[ifmt] == "S" || UserFormat[ifmt] == "E"))
    {
        if (EpisodeNumber[iepi] == UserFormat[ifmt])
        {
            ++iepi;
        }
        else if (!char.IsDigit(EpisodeNumber[iepi]))
        {
            // Error! Chars didn't match, and it wasn't a digit.
            break;
        }
        ++ifmt;
    }
    else
    {
        char c = EpisodeNumber[iepi];
        if (!char.IsDigit(c))
        {
            // error. Expected digit.
        }
        if (UserFormat[ifmt] == 'e')
        {
            episode = (episode * 10) + (int)c - (int)'0';
        }
        else if (UserFormat[ifmt] == 's')
        {
            season = (season * 10) + (int)c - (int)'0';
        }
        else
        {
            // user format is broken
            break;
        }
        ++iepi;
        ++ifmt;
    }
}

请注意,您可能需要进行一些检查,以查看长度是否正确。也就是说,当用户的格式为SssEee时,上面的代码将接受S01E1。您可以添加更多的错误处理,这取决于您对错误输入的担忧程度。但我认为这给了你这个想法的要点。

我不得不认为,这将比尝试动态构建正则表达式容易得多。

在@Sinametic回答了我的问题后,我们可以将他的原始帖子减少为:挑战在于接收以下任何输入:

  1. 0105(如果您的输入是0105,则假设SxxEy(
  2. S01E05
  3. E05S01
  4. 1x05(读作第1季第5集(

并将这些输入中的任何一个转换为:S01E05
在这一点上,标题和文件格式是无关紧要的,它们只是被钉在了末尾。

基于此,以下代码将始终生成"太空堡垒.卡拉狄加.S01E05.mkv">

  static void Main(string[] args)
  {
     string[] inputs = new string[6] { "E05S01", "S01E05", "0105", "105", "1x05", "1x5" };
     foreach (string input in inputs)
     {
        Console.WriteLine(FormatEpisodeTitle("Battlestar.Galactica", input, "mkv"));
     }

     Console.ReadLine();
  }

  private static string FormatEpisodeTitle(string showTitle, string identifier, string fileFormat)
  {
     //first make identifier upper case
     identifier = identifier.ToUpper();
     //normalize for SssEee & EeeSee
     if (identifier.IndexOf('S') > identifier.IndexOf('E'))
     {
        identifier = identifier.Substring(identifier.IndexOf('S')) + identifier.Substring(identifier.IndexOf('E'), identifier.IndexOf('S'));
     }
     //now get rid of S and replace E with x as needed:
     identifier = identifier.Replace("S", string.Empty).Replace("E", "X");

     //at this point, if there isn't an "X" we need one, as in 105 or 0105
     if (identifier.IndexOf('X') == -1)
     {
        identifier = identifier.Substring(0, identifier.Length - 2) + "X" + identifier.Substring(identifier.Length - 2);
     }
     //now split by the 'X'
     string[] identifiers = identifier.Split('X');
     // and put it back together:
     identifier = 'S' + identifiers[0].PadLeft(2, '0') + 'E' + identifiers[1].PadLeft(2, '0');
     //tack it all together 
     return showTitle + '.' + identifier + '.' + fileFormat;
  }