正则表达式获取第一个字符的索引而不是双引号

时间:2019-01-18 12:59:57

标签: c# .net regex string

我正在寻找正则表达式来执行以下操作:

  • 返回给定字符的第一个实例的索引,而不是在双引号内(我可以保证匹配的结束双引号将始终存在,并且要搜索的字符本身永远不会是双引号)
  • 允许从int startIndex位置开始

速度是我这里主要关注的问题之一,因此迭代次数应尽可能少。

示例(所有示例都设置为寻找!,但这并非总是如此):

  • !something-应该返回0
  • !也应返回0
  • something!应该返回9
  • "something!"应该失败
  • "some!thing"!应该返回12
  • !"!"!应该返回0
  • ""!应该返回2
  • ""!""应该返回2
  • !somethingstartIndex == 2应该失败
  • !something!startIndex == 2应该返回10(尽管从位置2开始,给定字符串上字符的索引仍然是10)

因为这是.NET的用意,所以将使用Regex.Match().Index(除非提供了更好的替代方法)。

2 个答案:

答案 0 :(得分:1)

我建议使用旧的for循环,而不要使用正则表达式;让我们将其实现为扩展方法:

  public static partial class StringExtensions {
    public static int IndexOfQuoted(this string value,
                                    char toFind,
                                    int startPosition = 0,
                                    char quotation = '"') {
      if (string.IsNullOrEmpty(value))
        return -1;

      bool inQuotation = false;

      for (int i = 0; i < value.Length; ++i)
        if (inQuotation)
          inQuotation = value[i] != quotation;
        else if (value[i] == toFind && i >= startPosition)
          return i;
        else
          inQuotation = value[i] == quotation;

      return -1;
    }
  }

因此,您可以像使用IndexOfQuoted的{​​{1}}方法一样使用它:

string

演示:

  string source = "something!";
  int result = source.IndexOfQuoted('!'); 

结果:

  string[] tests = new string[] {
    "!something",
    "!",
    "something!",
    "\"something!\"",
    "\"some!thing\"!",
    "!\"!\"!",
    "\"\"!",
    "\"\"!\"\"",
  };

  string report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test,-20} -> {test.IndexOfQuoted('!')}"));

  Console.Write(report);

答案 1 :(得分:0)

如果您确实需要正则表达式版本,则可以使用以下模式。

"(?<searchTerm>!)(?=(?:[^\"]|\"[^\"]*\")*$)"

示例,用于输入

var input = new []
    {
    new {Key= "!something", BeginIndex=0},
    new {Key= "!", BeginIndex=0},
    new {Key= "something!", BeginIndex=0},
    new {Key= "\"something!\"", BeginIndex=0},
    new {Key= "\"some!thing\"!", BeginIndex=0},
    new {Key= "!\"!\"!", BeginIndex=0},
    new {Key= "\"\"!", BeginIndex=0},
    new {Key= "\"\"!\"\"", BeginIndex=0},
    new {Key= "!something", BeginIndex=2},
    new {Key= "!something!", BeginIndex=2},
    new {Key="!\"some!thing\"!",BeginIndex=5}
    };

您可以按以下方式搜索索引

var pattern = "(?<searchTerm>!)(?=(?:[^\"]|\"[^\"]*\")*$)";
Regex regex = new Regex(pattern,RegexOptions.Compiled);
foreach(var str in input)
{
    var index = str.Key.GetIndex(regex,str.BeginIndex);
    Console.WriteLine($"String:{str.Key} , Index : {index}");
}

GetIndex定义为

public static class Extension
{
    public static int GetIndex(this string source,Regex regex,int beginIndex=0)
    {
        var match = regex.Match(source);
        while(match.Success)
        {   

            if(match.Groups["searchTerm"].Index >= beginIndex)
                return match.Groups["searchTerm"].Index;

            match = match.NextMatch();
        }
        return -1;
    }
}

输出

String:!something , Index : 0
String:! , Index : 0
String:something! , Index : 9
String:"something!" , Index : -1
String:"some!thing"! , Index : 12
String:!"!"! , Index : 0
String:""! , Index : 2
String:""!"" , Index : 2
String:!something , Index : -1
String:!something! , Index : 10
String:!"some!thing"! , Index : 13

希望有帮助。