2017-02-21 25 views
1

Я ищу строку для операторов. Мне нужно фактический оператор и его индекс в строкеПоиск подстроки в строке с использованием linq

Например: x>10&y>=10

Операторы

> 
& 
>= 
= 

Поэтому мне нужно результаты, как

> 1 
& 4 
>= 6 

Так что я написал такой код

string substr= "x>10&y>=10"; 
List<string> substringList = new List<string>{">", "&", ">=", "="}; 

var orderedOccurances = substringList 
     .Where((substr) => str.IndexOf(substr, StringComparison.Ordinal) >= 0) 
     .Select((substr, inx) => new 
      { substr, inx = str.IndexOf(substr, StringComparison.Ordinal) }) 
     .OrderBy(x => x.inx).ToList(); 

Однако я получил результаты, как это (очевидно)

> 1 
& 4 
> 6 
= 7 

Я могу использовать цикл для поиска и покрыть этот сценарий ошибки. Но мне нравится код короткой руки linq. В любом случае, я могу покрыть условие ошибки с помощью lambdas/linq?

+1

Где находится этот монструальный LINQ-оператор короче и, в частности, лучше читается, чем простой цикл foreach? – HimBromBeere

+0

Я вроде согласен с этим. Я все еще хотел бы знать, можно ли выполнить linq для этого сценария. – Jimmy

+2

Не делайте этого. Вам нужен лексер, поэтому напишите лексер. –

ответ

1

Поэтому в основном то, что вы хотите, чтобы просканировать последовательность для символов «<», «>», «=» и «&», и если какой-либо из них нашли помните индекс и найденный символ, если '< 'или'> ', вы хотите узнать, стоит ли после этого «=», и если это так, следующий поиск должен начинаться после «=».

Отметьте, что вы не указали какие вы хотите с &= или ==.

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

Согласно спецификации выше вы хотите регулярное выражение, которое соответствует, если вы обнаружите какие-либо из следующих действий:

  • '< ='
  • '> ='
  • '='
  • '&'
  • '<', за которым следует что-то еще, чем '='
  • '>' След. B у что-то другое, чем '='

кодекс будет простым:

using System.Text.RegularExpressions; 

string expression = ...; 
var regex = new RegularExpression("&|<=|>=|[<>][^=]"); 
var matches = regex.Matches(expression); 

matches Объект представляет собой массив Match объектов. Каждый match объект имеет свои свойства Index, Length и Value; именно те свойства, которые вы хотите.

foreach (var match in matches) 
{ 
    Console.WriteLine($"Match {match.Value} found" 
     + " at index {match.Index} with length {match.Length}"); 
} 

Вертикальная полоса | в регулярном выражении означает OR; [ ] означает любой из символов между скобками;; [^ ] означает НЕ любой из символов между скобками.

Так найдено совпадение, если либо & или <= или >= или любой символ в <>, который не сопровождается =.

Если вы хотите найти & = и ==, то ваше reguilar выражения будет еще проще:

  • найти <> & = что следует =
  • или найти какую-либо <> & =, не следуют =

Код:

var regex = new Regex("[<>&=]|[<>&=][^=]"); 

Хороший онлайн-тестер регулярных выражений, где вы можете проверить свое регулярное выражение can be found here. Это также показывает, какие совпадения найдены и описание синтаксиса регулярных выражений.

0

Ну, если вы согнуты на использование LINQ вы можете сделать следующее:

public static IEnumerable<(int Index, string Substring)> GetAllIndicees(this string str, IEnumerable<string> subtrings) 
{ 
    IEnumerable<(int Index, string Substring)> GetAllIndicees(string substring) 
    { 
     if (substring.Length > str.Length) 
      return Enumerable.Empty<(int, string)>(); 

     if (substring.Length == str.Length) 
      return Enumerable.Repeat((0, str), 1); 

     return from start in Enumerable.Range(0, str.Length - substring.Length + 1) 
       where str.Substring(start, substring.Length).Equals(substring) 
       select (start, substring); 
    } 

    var alloperators = subtrings.SelectMany(s => GetAllIndicees(s)); 
    return alloperators.Where(o => !alloperators.Except(new[] { o }) 
               .Any(other => o.Index >= other.Index && 
                   o.Index < other.Index + other.Substring.Length && 
                   other.Substring.Contains(o.Substring)));  
} 

с использованием C# 7 синтаксиса здесь becuase коды более краткие и читаемые, но его легко переводимые с предыдущими версиями.

А теперь, если вы:

var substr = "x>10&y>=10"; 
var operators = new HashSet<string>(new[] { ">", "&", ">=", "=" }); 
Console.WriteLine(string.Join(", ", filteredOperators.Select(o => $"[{o.Operator}: {o.Index}]"))); 

Вы получите ожидаемый результат:

[>: 1], [&: 4], [>=: 6] 

Является ли это "лучше", чем при использовании других инструментов? Я не совсем уверен.

1

Вот более общий вариант:

string str = "x>10&y>=10"; 

var result = Regex.Matches(str, @">=|>|&|=").Cast<Match>() 
    .Select(m => new { s = m.Value, i = m.Index }).ToList(); 

Результат:

> 1 
& 4 
>= 6 

или немного короче, если нет никаких других операторов в строке:

var d = Regex.Matches(str, @"\W+").Cast<Match>().ToDictionary(m => m.Index, m => m.Value); 

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

  • Нет связанных вопросов^_^