使用linq在字符串中搜索子字符串

时间:2017-02-21 14:44:12

标签: c# linq lambda

我正在寻找运营商的字符串。我需要字符串

中的实际运算符及其索引

例如: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

我可以使用for循环进行搜索并覆盖此错误场景。但我喜欢linq短手代码。无论如何我可以使用lambdas / linq覆盖错误条件吗?

3 个答案:

答案 0 :(得分:1)

所以基本上你想要的是扫描你的序列中的字符'lt'','&gt;','='和'&amp;',如果发现其中任何一个,请记住索引和找到的字符,如果'&LT;'或'&gt;'发现你想知道'='是否在它之后,如果是,那么下一次搜索应该在'='之后开始。

请注意,您未使用&===指定所需内容。

每当你必须扫描字符串以获得某种语法时,至少考虑使用正则表达式总是明智的。

根据上面的规范,如果您发现以下任何内容,则需要匹配的正则表达式:

  • '&LT; ='
  • '&GT; ='
  • '='
  • '&安培;'
  • '&LT;'其次是'='
  • 以外的东西
  • '&GT;'其次是'='
  • 以外的东西

代码很简单:

using System.Text.RegularExpressions;

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

对象matchesMatch个对象的数组。每个match对象都有属性IndexLengthValue;正是你想要的属性。

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

正则表达式中的竖线|表示OR; [ ]表示括号中的任意字符; [^ ]表示不是括号之间的任何字符。

如果&<=>=<>中没有=后面的任何字符,则会找到匹配。

如果你还想找到&amp; =和==,那么你的规则表达会更容易:

  • 找到任何&lt;&gt;&amp; =后面跟着=
  • 或找到任何&lt;&gt;&amp; =后面没有=

代码:

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

一个优秀的在线正则表达式测试程序,您可以在其中检查正则表达式can be found here。这也显示了找到的匹配项以及正则表达式语法的描述。

答案 1 :(得分: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);

答案 2 :(得分: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语法,因为这些代码更简洁,更易读,但可以轻松翻译到以前的版本。

现在,如果你这样做:

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]

这是&#34;更好&#34;比使用其他工具?我不太确定。