Разбить строку набором символов разделителей, включая эти символы в итоговый массив как элементы
Необходимо разбить строку определённым массивом символов разделителей char[], так чтобы эти символы тоже сохранились в итоговом массиве строк string[], как отдельные элементы. Разумеется, сохраняя исходный порядок.
Получилось реализовать только так:
public static class StringExtension
{
public static string[] SplitAndSaveSeparators(this string str, char[] separators)
{
string temp = str;
foreach (char chr in str)
if (separators.Contains(chr))
temp = temp.Replace($"{chr}", $"{'~'}{chr}{'~'}");
return temp.Split('~');
}
}
Очевидно, что это не самая лучшая реализация. Возможно получится реализовать с помощью регулярных выражений или же еще как-либо?
Ответы (2 шт):
Регулярками можно сделать так.
Заключаем разделители в круглые и квадратные скобки. Например, разделители , и ;. Тогда итоговое выражение должно выглядеть так: ([,;]).
Квадратные скобки означают набор символов, а круглые необходимы для использования алгоритма работы этого метода.
Цитата из документации:
Если в выражении Regex.Split используются скобки, любой захваченный текст включается в результирующий массив строк.
Не забываем об экранировании специальных символов: \, [ - для этого пропускаем разделители через Regex.Escape. Если таковых гарантированно не будет, то можно это пропустить.
using System.Text.RegularExpressions;
string str = "ab,cd,;ef";
char[] separators = [',', ';'];
string escaped = Regex.Escape(new string(separators));
string pattern = $"([{escaped}])";
var result = Regex.Split(str, pattern)
.Where(x => x.Length > 0);
foreach (var x in result)
Console.WriteLine(x);
Если в исходной строке str могут идти несколько разделителей подряд: ,;, то после расщепления в результате будут пустые строки. Удаляем их с помощью Where. Можно его убрать, если такого гарантированно не случится.
Кстати, в вашей функции в этом случае следует добавить параметр StringSplitOptions.RemoveEmptyEntries в вызов Split.
using System;
using System.Collections.Generic;
static class Program {
static List<string> GetDelimited(string researched, char[] sought) {
int i = 0, j;
var res = new List<string>();
while ((j = researched.IndexOfAny(sought, i)) > -1) {
if (j > i) res.Add(researched.Substring(i, j - i));
res.Add(researched.Substring(j, 1));
i = j + 1;
}
if (i < researched.Length) res.Add(researched.Substring(i, researched.Length - i));
return res;
}
static string GetFromConsole() { Console.Write("> "); return Console.ReadLine(); }
static void Main() {
var sc = new char[] { ',', ';' };
string instr;
while ((instr = GetFromConsole()) != "\t") // TAB to end
foreach (var s in GetDelimited(instr, sc)) Console.WriteLine(s);
}
}