【问题标题】:How do I find a pattern in a string?如何在字符串中找到模式?
【发布时间】:2018-10-20 05:48:31
【问题描述】:

想象一下你有这样的字符串

o7o7o7o7o7o

o7o的明确模式 我的方法是在第一个 o 之后找到第二个 o,这就是模式,然后看看它是否匹配。

字符串是,如何获取第二个o的索引?

我试过了

var pattern = "o7o7o7o7o7o";
var index = input.IndexOf("*");

但这显然会得到它找到的第一个o 的第一个索引,我想得到第二个。 我该怎么做?

【问题讨论】:

  • 您想从上面的字符串中获取7 之后的o 的索引吗?
  • 是的,这正是我想要的
  • 你没有指定inputpattern.IndexOf("*") 会给你-1。我发现这个问题不清楚,你想找到一个模式还是测试一个?

标签: c# .net string algorithm pattern-matching


【解决方案1】:

您可以通过多种方式做到这一点,最快的方式是循环

string pattern = "o7o7o7o7o7o";
int count = 0;
int index = 0;
while(index < pattern.Length)
{
     if(pattern[index] == 'o') count++;
     if(count == 2) break;
     index++;
}

index 就是你想要的。

Linq:

int index = pattern.Select((x, i) => new { x, i })
              .Where(a => a.x == 'o').Skip(1)
              .FirstOrDefault().i;

string.IndexOf():

int count = 0, index = 0;
do
{
    index = pattern.IndexOf('o', index);
    if (index != -1) { count++; index++; }
} while (index != -1 && count < 2);

还有很多其他方式,但我认为上面三个例子会很好,因为我想到的其他方式比较慢(至少我能想到的那些)。

【讨论】:

  • 如果你有一个看起来像 "o7o7oo7o7o7o" 的字符串会使其不均匀,有没有办法识别它?
  • 如果您的意思是获取第二个o 的索引,是的,所有这些示例都有效,无论模式如何,如果这不是您的意思,请告知。
【解决方案2】:

也可以像这样使用正则表达式:

var pattern = "o7o7o7o7o7o";

var regex = new Regex("7(o)");

var matches = regex.Matches(pattern);

foreach (Match match in matches)
{
    Console.WriteLine(match.Groups[1].Index);
}

【讨论】:

  • 我认为 7(o) 给出了 OP 想要的输出而不是 o7(o)
  • 他说“在第一个 o 之后找到第二个 o”,这将完成,以及系列中的每个。除非我没有正确理解这个问题。
  • 是的,他想在 7 之后获得 o 的索引。阅读有问题的 cmets。
  • 啊没注意到,你是对的。改变了答案。
【解决方案3】:

构建前缀函数并寻找压缩表示为described here

给定一个长度为 n 的字符串 s。我们想找到最短的 字符串的“压缩”表示,即我们想要找到一个 最小长度的字符串 t,使得 s 可以表示为 一个或多个 t 副本的连接。

很明显,我们只需要找到 t 的长度。知道 长度,问题的答案将是 s 的前缀与 this 长度。

让我们计算 s 的前缀函数。使用它的最后一个值 我们定义值 k=n−π[n−1]。我们将证明,如果 k 除以 n, 那么 k 就是答案,否则不存在有效的 压缩,答案是 n。

但是您的字符串不能表示为 (u)^w,因为它末尾有过多的字符。在这种情况下,检查 (i+1) 的可分性 (我是索引)(i-p[i])

对于s = '1231231231',我们可以得到(123)^3+1 的表示,因为最后一个可以被k[i]=3 整除的(i+1) 是9

  i+1: p[i] k[i]
  1 : 0  1 
  2 : 0  2 
  3 : 0  3 
  4 : 1  3 
  5 : 2  3 
  6 : 3  3 
  7 : 4  3 
  8 : 5  3 
  9 : 6  3 
  10 : 7  3 

【讨论】:

    【解决方案4】:

    要在至少 1 次而不是 o 之间获取第二次出现 o 的索引,您可以使用正则表达式和捕获组并获取该组的索引:

    ^[^o]*o[^o]+(o)

    那会匹配:

    • ^断言字符串的开头
    • [^o]* 匹配 0+ 次而不是 o 使用否定字符类
    • o 从字面上匹配 o
    • [^o]+ 匹配 1+ 次而不是使用否定字符类的 o(如果还可以有 2 个连续的 o,则使用 [^o]*)。
    • (o) 在群组中捕获o

    Regex demo

    string pattern = @"^[^o]*o[^o]+(o)";
    string input = @"o7o7o7o7o7o";
    
    Match m = Regex.Match(input, pattern);
    Console.WriteLine(m.Groups[1].Index); // 2
    

    Demo c#

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多