配列内の指定文字列を結合する

やりたいこと

指定文字列をABとした時
{"x", "A", "B", "AB"} ⇒ {"x", "AB", "AB"}
のような配列を作成する。

処理フロー

配列の要素を取り出す。

  1. 指定文字列を含む⇒そのまま追加※
  2. 指定文字列を含まない
    1. 末尾が指定文字列の先頭の一部と一致する。⇒次の要素を結合して比較
    2. 末尾が指定文字列の先頭の一部と一致しない。⇒そのまま追加

ここで、{"ABA","B"}を考える。
この場合、{"ABA","B"}は※に該当するため、{"ABA", "B"}となってしまう。
そこで、指定文字列を含む場合は"AB"文字列を分割する必要がある。
これには以下を使用する。
これによって、分割した配列の末尾を新たな要素として同様の処理を行えばよい。

internal static List<string> SplitByPattern(List strs, string pattern)
{
  var ret = new List<string>();
  
  var sb = new StringBuilder();
  var strNumber = strs.Count;
  
  for (int i = 0; i < strNumber; ++i)
  {
    sb.Clear();
    var str = strs[i];
    // 指定文字列を含む
    if (str.Contains(pattern))
    {
      var splits = SplitStrByPattern(str, pattern);
      var lastStr = splits.Last();
      splits.RemoveAt(splits.Count - 1);
      foreach (var split in splits)
        ret.Add(split);
      
      if (lastStr.Contains(pattern))
      {
        ret.Add(lastStr);
        continue;
      }
      str = lastStr;
    }
    // 末尾がパターンの先頭の一部と一致しない
    if (!TailContainPartOfHeadIndex(str, pattern))
    {
      ret.Add(str);
      continue; // 次に進む
    }
    
    // 後続要素をループで追加して同様の処理を行う
    sb.Append(str);
    for (int j = i + 1; j < strNumber; ++j)
    {
      sb.Append(strs[j]);
      var joinStr = sb.ToString();
      
      // パターンを含む
      if (joinStr.Contains(pattern))
      {
        var splits = SplitStrByPattern(joinStr, pattern); // 末尾以外は区切られている
        var lastStr = splits.Last();
        splits.RemoveAt(splits.Count - 1);
        foreach (var split in splits)
          ret.Add(split);

        if (lastStr.Contains(pattern))
        {
          ret.Add(lastStr);
          i = j;
          break;
        }

        joinStr = lastStr;
        sb.Clear();
        sb.Append(joinStr);
      }
      
      // 末尾がパターンの先頭の一部と一致しない
      if (!TailContainPartOfHeadIndex(joinStr, pattern))
      {
        ret.Add(joinStr);
        i = j;
        break;
      }
    }
  }
  return ret;
}

internal static bool TailContainPartOfHeadIndex(string str, string pattern)
{
  var patternLen = pattern.Length;
  for (int i = 1; i <= patternLen; ++i)
  {
    if (str.EndsWith(pattern.Substring(0, i)))
      return true;
  }
  return false;
}