Несмотря на ваше нежелание использовать регулярные выражения, на самом деле он прекрасно сохраняет разделители, используя группу вместе с методом Regex.Split
:
string input = "123xx456yy789";
string pattern = "(xx|yy)";
string[] result = Regex.Split(input, pattern);
Если вы удалите скобки из шаблона, используя только "xx|yy"
, разделители не сохранятся. Обязательно используйте Regex.Escape в шаблоне, если вы используете метасимволы, которые имеют специальное значение в регулярном выражении. Символы включают \, *, +, ?, |, {, [, (,), ^, $,., #
. Например, разделитель .
должен быть экранирован \.
. Имея список разделителей, вам нужно «ИЛИ» использовать символ «|
», и это тоже символ, который экранируется. Чтобы правильно построить шаблон, используйте следующий код (спасибо @gabe за это):
var delimiters = new List<string> { ".", "xx", "yy" };
string pattern = "(" + String.Join("|", delimiters.Select(d => Regex.Escape(d))
.ToArray())
+ ")";
Круглые скобки объединены, а не включены в шаблон, поскольку они будут неправильно экранированы для ваших целей.
РЕДАКТИРОВАТЬ: Кроме того, если список delimiters
окажется пустым, окончательный шаблон будет неправильно ()
, и это приведет к пустым совпадениям. Чтобы предотвратить это, можно использовать проверку разделителей. Учитывая все это, фрагмент становится следующим:
string input = "123xx456yy789";
// to reach the else branch set delimiters to new List();
var delimiters = new List<string> { ".", "xx", "yy", "()" };
if (delimiters.Count > 0)
{
string pattern = "("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d))
.ToArray())
+ ")";
string[] result = Regex.Split(input, pattern);
foreach (string s in result)
{
Console.WriteLine(s);
}
}
else
{
// nothing to split
Console.WriteLine(input);
}
Если вам необходимо сопоставление регистров без учета регистра, используйте параметр RegexOptions.IgnoreCase
: Regex.Split(input, pattern, RegexOptions.IgnoreCase)
РЕДАКТИРОВАТЬ # 2: решение до сих пор соответствует разделенным токенам, которые могут быть подстрокой большей строки. Если разделенный токен должен соответствовать полностью, а не части подстроки, например, в сценарии, где слова в предложении используются в качестве разделителей, то вокруг шаблона должен быть добавлен метасимвол границы \b
.
Например, рассмотрим это предложение (да, это банально): "Welcome to stackoverflow... where the stack never overflows!"
Если бы разделителями были { "stack", "flow" }
, то текущее решение разделило бы "stackoverflow" и вернуло бы 3 строки { "stack", "over", "flow" }
. Если вам нужно точное совпадение, то единственное место, где будет разделяться это слово, будет слово «стек» в предложении, а не «стек-поток».
Чтобы добиться точного соответствия, измените шаблон так, чтобы он включал \b
, как в \b(delim1|delim2|delimN)\b
:
string pattern = @"\b("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d)))
+ @")\b";
Наконец, если требуется обрезать пробелы до и после разделителей, добавьте \s*
вокруг шаблона, как в \s*(delim1|delim2|delimN)\s*
. Это может быть объединено с \b
следующим образом:
string pattern = @"\s*\b("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d)))
+ @")\b\s*";