c #: регулярное выражение, как различать два варианта строки - PullRequest
0 голосов
/ 13 мая 2011

Это сложно объяснить достаточно, чтобы задать вопрос, но я попробую:

У меня есть две возможности пользовательского ввода:

S01E05 или 0105 (две разные строки ввода)

, которые оба переводятся в сезон 01, эпизод 05

, но если они вводят его в обратном направлении E05S01 или 0501, мне нужно иметь возможность вернуть тот же результат, сезон 01, эпизод 05

Элементом управления для этого будет пользователь, определяющий формат исходного имени файла примерно так: «SssEee» - прописные буквы «S», обозначающие принадлежность следующих строчных букв «Season», и прописные буквы «E», обозначающие, чтоСледующие строчные 'е' принадлежат Эпизоду.Так что, если пользователь решит определить формат как EeeSss, тогда моя функция все равно должна вернуть тот же результат, так как он знает, какие числа принадлежат сезону или эпизоду.

У меня пока нет ничего работающего, чтобы поделиться, ноя играл с циклом, который строит шаблон регулярных выражений.Пока что функция принимает формат пользователя и имя файла:

public static int(string userFormat, string fileName)
{

}

userFormat будет строкой и будет выглядеть примерно так:

tttSssEee

или даже

t.SssEee

где t для заголовка, а остальное вы знаете.

Имя файла можетвыглядят так:

battlestar.galactica.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
  • Создание выражения регулярного выражения, которое описывает это
  • Поиск по имени файла и поиск этого шаблона
  • Извлечение числа из этого шаблона

Звучит простоДостаточно, но я испытываю затруднения, заставляя это действоватьСложность заключается в том, что формат имени файла может быть S01E05 или просто 0105. Любой сценарий будет определен пользователем при определении формата.

Пример 1. файлимя Battlestar.galactica.S01E05

отправленный пользовательский формат будет tt? ss? ee

Ex 2. имя файла battlestar.galactica.0105

отправленный пользовательский формат будет ttSssEee

Ex 3. имя файла battlestar.galactica.0501

отправленный пользовательский формат будетttEeeSss

Извините за книгу ... концепция проста, функция регулярного выражения должна быть динамической, позволяющей пользователю определять формат имени файла, в котором мой метод может сгенерировать выражение, и использовать его для извлеченияинформация из имени файла.Что-то говорит мне, что это проще, чем кажется ... но я в растерянности.лол ... есть предложения?

Ответы [ 2 ]

1 голос
/ 13 мая 2011

Так что, если я правильно понял, вы знаете, где находится номер сезона / эпизода в строке, потому что пользователь сказал вам.То есть у вас есть 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;
    }
}

Обратите внимание, что вам, вероятно, придется выполнить некоторую проверку, чтобы убедиться, чтодлины правильные.То есть приведенный выше код примет S01E1, когда формат пользователя SssEee.Вы можете добавить немного больше обработки ошибок, в зависимости от того, насколько вы обеспокоены неправильным вводом.Но я думаю, что это дает вам суть идеи.

Я должен думать, что это будет намного проще, чем пытаться динамически создавать регулярные выражения.

0 голосов
/ 13 мая 2011

После того, как @Sinaesthetic ответил на мой вопрос, мы можем сократить его исходное сообщение до: Задача состоит в том, чтобы получить любой из этих входных данных:

  1. 0105 (если вы вводите 0105, вы предполагаете SxxEyy)
  2. S01E05
  3. E05S01 ИЛИ
  4. 1x05 (читается как эпизод 1 сезона 5)

и преобразованиелюбой из этих входных данных в: S01E05
На этом этапе заголовок и формат файла не имеют значения, они просто привязаны к концу.

Исходя из этого, следующий код всегда будет приводитьв «Battlestar.Galactica.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;

  }
...