Регулярное выражение для сопоставления целых чисел

1

У меня есть строка ввода:

"Monday 11:30am,11 v 2,3 v 4"

Мне нужно заменить:

  • 11 с Hurricanes
  • 2 с Team abc
  • 3 с Vipers
  • 4 с Dodgers
  • 1 с Frozen Rope

и так далее....

Но я не хочу заменять 1 дважды в 11.

У меня явно нет понимания регулярного выражения. Но я пробовал что-то вроде этого:

string text = File.ReadAllText(CSVpath);
text = Regex.Replace(text,
                     string.Format(@"[{0} v]", CurrentCode),
                     string.Format(@"{0} v", TeamName));
text = Regex.Replace(text,
                     string.Format(@"[v {0}]", CurrentCode),
                     string.Format(@"v {0}", TeamName));

Основываясь на этой входной строке выше, выход будет:

"Monday 11:30am,Hurricanes v Team abc,Vipers v Dodgers"
Теги:

5 ответов

3

Попробуйте это регулярное выражение:

var subject = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var replaced = Regex.Replace(subject,@"(\d+)\s*v\s*(\d+)","Team$1 with Team$2");

Разрыв шаблона:

  • (\d+) фиксирует последовательность чисел и сохраняет их в группе 1
  • \s*v\s* проверяет v обертку символов на ноль или более пробелов обеих сторон.
  • (\d+) фиксирует последовательность чисел и сохраняет их в группе2

Замена:

$1 заменяет первую группу командой и совпадением первой группы. Таким образом, 11 будет заменено Team11, затем складывает буквальный with и Team буквальной с $2 присоединяет матч group2.

Вот демонстрация Regex101

  • 1
    +1 за включение объяснения шаблона.
1

Это должно сделать трюк: \d{1,2} (обратите внимание на пустой символ в конце!)

0

Ваш начальный вопрос читался так, как будто вы хотели получить фиксированный формат "Teamnn" для вывода, но ваше редактирование значительно изменилось, так что вы хотите заменить имена команд.

Первое, что нужно сделать, это определить ваш поиск по номеру команды до имени команды. Я сделал это здесь с помощью простого массива "тривиального" класса 1 но вы можете выбрать что-нибудь для их хранения, возможно, даже базу данных, если числа будут достаточно большими, хотя я сомневаюсь, что здесь дело. Важно то, что это таблица поиска.

class Team
{
    public string Id { get; set; }
    public string Name { get; set; }
}
static Team[] teams = { 
    new Team { Id = "11", Name = "Hurricanes" },
    new Team { Id = "2",  Name = "Team abc" },
    new Team { Id = "3",  Name = "Vipers" },
    new Team { Id = "4",  Name = "Dodgers" },
    new Team { Id = "1",  Name = "Frozen Rope" },
};

Теперь определите соответствие шаблонов. Регулярное выражение

Regex regex = new Regex(@"(\d+)\s*v\s*(\d+)");

будет соответствовать:

  • (\d+) - последовательность цифр и захват для замены позже
  • \s* - возможно, некоторые пробелы
  • v - буква v
  • \s* - возможно, еще несколько пробелов
  • (\d+) - еще одна последовательность цифр и захват ее для замены позже

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

public string Test()
{
    string text = "Monday 11:30am,11 v 2,3 v 4";
    foreach (Match match in regex.Matches(text))
    {
        // For the first team in the fixture:
        string team1Id = match.Groups[1].Value; // get the id from the text
        Team team1 = teams.FirstOrDefault(t => t.Id == team1Id); // look it up
        string team1Name = team1.Name; // get the team name
        // For the second team in the fixture:
        string team2Id = match.Groups[2].Value; // get the id from the text
        Team team2 = teams.FirstOrDefault(t => t.Id == team2Id); // look it up
        string team2Name = team2.Name; // get the team name
        // Replace the whole matched string (with numbers)...
        string fixtureWithNumbers = match.Groups[0].Value;
        // ... with the equivalent with team names.
        string fixtureWithNames = team1Name + " v " + team2Name;
        text = text.Replace(fixtureWithNumbers, fixtureWithNames);
    }
    return text;
}

Это выписано из рук в руки. Разумеется, вы можете уменьшить его до немного меньшего размера, например:

public string Test2(string text)
{
    foreach (Match m in Regex.Matches(text, @"(\d+)\s*v\s*(\d+)"))
    {
        text = text.Replace(match.Groups[0].Value,
                            teams.FirstOrDefault(t => t.Id == m.Groups[1].Value)
                                 .Name +
                            " v " +
                            teams.FirstOrDefault(t => t.Id == m.Groups[2].Value)
                                 .Name);
    }
    return text;
}

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

Альтернативный подход заключается в замене цикла foreach и выполнении цикла в классе Regex с помощью MatchEvaluator. (Я благодарю Далорзо за предложение такого подхода). Для этого я изменил регулярное выражение на ((?<T>\d+)(?=\s*v))|((?<=v\s*)(?<T>\d+)):

  • (?<T>\d+) - последовательность цифр и фиксировать ее как именованный элемент (T) для замены позже
  • (?=\s*v) - где за ним следует некоторое (или ни одно) пустое пространство и буква v
  • | -или-
  • (?<=v\s*) - где ему предшествует буква v за которой следует некоторое (или ни одно) пустое пространство
  • (?<T>\d+) - последовательность цифр и фиксировать ее как именованный элемент (T) для замены позже

Выражения lookahead и lookbehind предполагают, что имя или день никогда не будут заканчиваться буквой v (true на английском языке и, вероятно, хотя бы на нескольких других языках, но не обязательно во всех), но в то же время допускают переменные пробелы либо шириной v между номерами команд. Если это пробел определенно исправлено, это можно использовать для улучшения строк lookahead и lookbehind.

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

Получившийся код выглядит следующим образом:

static Dictionary<string, string> teamDb =
    teams.ToDictionary(t => t.Id, t => t.Name);
public static void Test3(string text)
{
    var result = Regex.Replace(text,
                                @"((?<T>\d+)(?=\s*v))|((?<=v\s*)(?<T>\d+))",
                                new MatchEvaluator(
                                    m => teamDb[m.Groups["T"].Value]
                                ));
    Console.WriteLine("Test3: {0}", result);
}

Во всех трех случаях код по-прежнему имеет нерешенную проблему, если входная строка содержит номер команды, который не отображается в таблице поиска (при NullReferenceException программы с NullReferenceException при попытке получить Name), но решение, которое потребует решения по что вы хотели бы добавить в выходную строку, если это произойдет.

-
1 Нет такой вещи, как тривиальная программа.

  • 0
    Downvoter: Я открыт для конструктивных комментариев относительно того, как улучшить этот ответ.
0

Из http://msdn.microsoft.com/en-us/library/20bw873z(v=vs.110).aspx, который, как представляется, в основном соответствует синтаксису regex на других языках, вы можете использовать "\ d+ "для соответствия одной или нескольким десятичным разрядам.

Я не создал для вас правильное регулярное выражение, так как ваш вопрос касался только сопоставления заданного единого шаблона (11 вместо 1).

0

Вот моя версия:

/((\d+)(\b)(?![:]))/g

Что будет работать как:

string text = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var result = Regex.Replace(text, @"((\d+)(\b)(?![:]))", "Team$1");

Демо-версия

\d+ будет записывать как можно больше чисел.
(\b)(?![:]) исключает числа, связанные со временем, путем поиска :
(\b) требуется из-за того, что известно как жадное поведение +. Чтобы убедиться, что оценка в перспективе оценивается, требуется целое число \b.

Или на основе вашего редактирования:

string text = "Monday 11:30am,11 v 2,3 v 4,5 v 6";
var result = Regex.Replace(text, @"((\b)([\d]+)(\b)(?![:]))", new MatchEvaluator(
delegate(Match m)
{
    return "Team" + m.Value;   /*take value and find the proper team;*/
} ));
  • 0
    Хорошо, я сделаю: вопрос изменился, и ваш ответ больше не применим.
  • 0
    @ClickRick даже с обновлением ответ стоит. Вы удосужились прочитать и попробовать?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню