【问题标题】:Finding longest common matching substring from given List<string> in a string从字符串中的给定 List<string> 中查找最长的公共匹配子字符串
【发布时间】:2018-12-01 05:24:25
【问题描述】:

我有一个字符串列表,我想在给定字符串中找到它们出现的开始和结束索引。

我想找到原始字符串中存在的最长公共子字符串并只打印它。

这是我的代码:

public static void Main(string[] args)
{
    //This is my original string where I want to find the occurance of the longest common substring
    string str = "will you consider the lic premium of my in-laws for tax exemption";

    //Here are the substrings which I want to compare   
    List<string> subStringsToCompare = new List<string>
    {
        "Life Insurance Premium",
        "lic",
        "life insurance",
        "life insurance policy",
        "lic premium",
        "insurance premium",
        "insurance premium",
        "premium"
    };

    foreach(var item in subStringsToCompare)
    {
        int start = str.IndexOf(item);

        if(start != -1)
        {
            Console.WriteLine("Match found: '{0}' at {1} till {2} character position", item, start, start + item.Length);
        }
    }
}

问题是我出现了 3 次而不是 1 次。我似乎无法弄清楚它从所有子字符串中获取最长的公共匹配子字符串以进行比较的条件。

我得到的输出:

  • 找到匹配项:“lic”在 22 到 25 个字符位置
  • 找到匹配项:“lic premium”在 22 到 33 个字符位置
  • 找到匹配项:“premium”在 26 到 33 个字符位置

预期输出:

  • 找到匹配项:“lic premium”在 22 到 33 个字符位置

.NET Fiddle

【问题讨论】:

  • 您不能按长度(降序)对subStringsToCompare 进行排序并在找到的第一个匹配项时退出吗?这样,“lic premium”将首先找到并在“lic”和“premium”进入 foreach 循环之前显示。
  • @vc 在我看来并不是万无一失的
  • 什么意思?
  • @vc74 我的意思是它仍然在循环后面寻找licpremium。如果我得到了比赛怎么解救?这是updated fiddle
  • 我添加了一个答案来说明我的意思

标签: c# arrays string substring longest-substring


【解决方案1】:

这是我在评论中的建议

public static void Main(string[] args)
{
    //This is my original string where I want to find the occurance of the longest common substring
    string str = "will you consider the lic premium of my in-laws for tax exemption";

    // Here are the substrings which I want to compare
    // (Sorted by length descending) 
    List<string> subStringsToCompare = new List<string>
    {
        "Life Insurance Premium",
        "life insurance policy",
        "insurance premium",
        "life insurance",
        "lic premium",
        "premium",
        "lic"
    };

    foreach(var item in subStringsToCompare)
    {
        int start = str.IndexOf(item);

        if(start != -1)
        {
            Console.WriteLine("Match found: '{0}' at {1} till {2} character position", item, start, start + item.Length);

            break; // Stop at the first match found
        }
    }
}

【讨论】:

    【解决方案2】:

    如果您只需要字符串列表中的完全匹配(而不是列表中字符串的子字符串),那么您非常接近

    string longest = null;
    int longestStart = 0;
    foreach(var item in subStringsToCompare)
    {
        int start = str.IndexOf(item);
    
        if(start != -1 && (longest == null || item.Length > longest.Length))
        {
            longest = item;
            longestStart = start
        }
    }
    
    if (longest != null)
    {
        Console.WriteLine("Match found: '{0}' at {1} till {2} character position", longest, longestStart, longestStart + longest.Length);
    }
    

    【讨论】:

      【解决方案3】:

      我没有尝试过,但请尝试以下方法:

      List<string> matches = new List<string>();
      for( int i = 0; i < str.Length; i++ )
      {
          foreach ( string toCompare in subStringsToCompare )
          {
              if ( str.SubString( i, toCompare.Length ) == toCompare )
                  matches.Add( toCompare );
          }
      }
      
      string longest = "";
      foreach ( string match in matches )
      {
          if ( match.Length > longest.Length )
              longest = match;
      }
      

      【讨论】:

      • 这会进一步增加复杂性,导致不必要的计算。
      • 您能解释一下为什么您认为您的更改更好吗?因为它是我们猜测你为什么认为这是一个改进。例如,我看不出逐个字符地遍历字符串、找到子字符串并比较它们有什么优势,而不是像 OP 最初那样使用 .indexof。
      • “更改”?我的回答是没有改变一些不存在的代码......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      • 2021-02-14
      • 2022-01-09
      • 2015-03-31
      相关资源
      最近更新 更多