配列内の指定文字列を結合する
やりたいこと
指定文字列をABとした時
{"x", "A", "B", "AB"} ⇒ {"x", "AB", "AB"}
のような配列を作成する。
処理フロー
配列の要素を取り出す。
- 指定文字列を含む⇒そのまま追加※
- 指定文字列を含まない
- 末尾が指定文字列の先頭の一部と一致する。⇒次の要素を結合して比較
- 末尾が指定文字列の先頭の一部と一致しない。⇒そのまま追加
ここで、{"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;
}