2015-01-15 3 views
2

Я ищу для извлечения:Regex заменить все, кроме определенного шаблона

50%

Из строки, которая будет иметь более или менее этот формат:

The 50% is in here somewhere.

Я также хотели бы извлечь:

50%50%25%

Из строки, как это:

50% of 50% is 25%

Regex.Match() кажется очевидным соперником. Однако это включает проверку наличия совпадений (например, match.Success), извлечение результатов из определенного индекса в массиве и/или риск обращения к индексу вне пределов.

Обычно замену Regex проще применять. Одна строка выполняет задание, включая возврат результирующей строки. Это верно для многих языков.

result = Regex.Replace(input, stuffWeDontLike, "")

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

percentages = Regex.Filter("50% of 50% is 25%", "[0-9]+\%")

Можем ли мы сформировать регулярное выражение и инвертировать результат, как если бы это был выбор? Это позволило бы использовать регулярное выражение. Однако я не мог найти способ легко инвертировать регулярное выражение.

Как мы можем достичь желаемого результата (или аналогичного, соединение или так кажется приемлемым) с очень коротким и простым синтаксисом, похожим на регулярное выражение?

+0

Итак, хотите ли вы ЗАМЕНИТЬ ИЛИ ВЫРАЖАТЬ в конце? Экстракция выполняется с помощью групп (скобки) и проверки совпадений в регулярных выражениях. Группы – Kilazur

+0

Я хочу извлечь, но как однострочный. – Timo

ответ

1

Вы можете использовать Regex.Matches и соединить результат каждого совпадения. Просто выберите тот, который вам нравится больше всего.

//Sadly, we can't extend the Regex class 
public class RegExp 
{ 
    //usage : RegExp.Filter("50% of 50% is 25%", @"[0-9]+\%") 
    public static string Filter(string input, string pattern) 
    { 
     return Regex.Matches(input, pattern).Cast<Match>() 
      .Aggregate(string.Empty, (a,m) => a += m.Value); 
    } 
} 

public static class StringExtension 
{ 
    //usage : "50% of 50% is 25%".Filter(@"[0-9]+\%") 
    public static string Filter(this string input, string pattern) 
    { 
     return Regex.Matches(input, pattern).Cast<Match>() 
      .Aggregate(string.Empty, (a,m) => a += m.Value); 
    } 
} 
+0

Однострочники. На что я надеялся! В контексте нескольких разработчиков фрагмент был более подходящим. Теперь я вставляю 'Regex.Matches (input, pattern) .Cast () .Aggregate (" ", (s, m) => s + m.Value);' Это решение передает намерения лучше, чем мое замещение, будучи очень кратким. – Timo

1

Одно из решений состоит в использовании регулярных выражений заменить следующим образом:

Regex.Replace("50% of 50% is 25%", "(\d+\%)|(?:.+?)", "$1");

Выход:

50%50%25%

В качестве общего подхода:

Regex.Replace(input, (pattern)|(?:.+?), "$1");

Это находит все, что соответствует любому из следующих элементов:

  • Узор. Захвачено как $1. Это то, что мы хотим сохранить.
  • Любой персонаж, любое количество раз, но не жадный. Это находит что-то, что не, снятое первой группой. ?:, потому что нам не нужно захватывать эту группу.

Как заявляет MSDN: «$1 заменяет полное совпадение первым захваченным подвыражением». (То есть все совпадения для этой подстроки, конкатенированные.)

Эффективно это описанный фильтр регулярных выражений.

+0

Я удалил свой другой комментарий. Но ... что было бы неправильно с '(pattern) | .' вместо' (pattern) | (?:. +?) ', А затем все еще использовать' $ 1' в разделе замены? –

+0

Я считаю, что это должно сработать. У меня была догадка, что один «. +?» Будет быстрее, чем повторять «.», Чтобы очистить куски неинтересных персонажей за раз, но я вполне мог бы ошибиться. – Timo

2

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

Просто используйте Matches() для получения матчей. Вы могли бы присоединиться к ним в строку, которую вы хотели.

var str = "50% of 50% is 25%"; 
var re = new Regex(@"\d+%"); 
var ms = re.Matches(str); 
var values = ms.Cast<Match>().Select(m => m.Value); 
var joined = String.Join("", values); // "50%50%25%" 
+0

Я обрушил это на 'String.Join (" ", Regex.Matches (str, @" [0-9] + \% "). Cast () .Выберите (m => m.Value)); решение с использованием 'Aggregate()' в конце, поскольку оно поддерживает логический порядок чтения даже в одной строке. – Timo

+0

Btw, '[0-9]' не может быть свободно заменен на '\ d', потому что последнее также соответствует вещам, таким как арабские цифры. Я использовал '[0-9]' специально. – Timo

Смежные вопросы