С# разделите строку, но сохраните раздельные символы/разделители

Я разделяю строку на три разных символа, но я хочу, чтобы на выходе включались символы, которые я разделял. Есть ли простой способ сделать это?

Ответ 1

Если разделительные символы были ,, . и ;, я бы попробовал:

string[] parts = Regex.Split(originalString, @"(?<=[.,;])")

(?<=PATTERN) - положительный внешний вид для PATTERN. Он должен совпадать в любом месте, где предшествующий текст соответствует PATTERN, поэтому после каждого появления любого из символов должно быть соответствие (и разделение).

Ответ 2

С учетом ответа BFree у меня была та же цель, но я хотел разбить массив символов, похожий на оригинальный метод Split, и у меня также есть несколько разделов на строку:

public static IEnumerable<string> SplitAndKeep(this string s, char[] delims)
{
    int start = 0, index;

    while ((index = s.IndexOfAny(delims, start)) != -1)
    {
        if(index-start > 0)
            yield return s.Substring(start, index - start);
        yield return s.Substring(index, 1);
        start = index + 1;
    }

    if (start < s.Length)
    {
        yield return s.Substring(start);
    }
}

Ответ 3

На всякий случай кто-то хочет получить этот ответ...

Вместо string[] parts = Regex.Split(originalString, @"(?<=[.,;])") вы можете использовать string[] parts = Regex.Split(originalString, @"(?=yourmatch)"), где yourmatch - это ваш разделитель.

Предположим, что исходная строка была

777- cat

777 - собака

777 - мышь

777 - крыса

777 - волк

Regex.Split(originalString, @"(?=777)") вернет

777 - cat

777 - собака

и т.д.

Ответ 4

Это, похоже, работает, но его не тестировали много.

public static string[] SplitAndKeepSeparators(string value, char[] separators, StringSplitOptions splitOptions)
{
    List<string> splitValues = new List<string>();
    int itemStart = 0;
    for (int pos = 0; pos < value.Length; pos++)
    {
        for (int sepIndex = 0; sepIndex < separators.Length; sepIndex++)
        {
            if (separators[sepIndex] == value[pos])
            {
                // add the section of string before the separator 
                // (unless its empty and we are discarding empty sections)
                if (itemStart != pos || splitOptions == StringSplitOptions.None)
                {
                    splitValues.Add(value.Substring(itemStart, pos - itemStart));
                }
                itemStart = pos + 1;

                // add the separator
                splitValues.Add(separators[sepIndex].ToString());
                break;
            }
        }
    }

    // add anything after the final separator 
    // (unless its empty and we are discarding empty sections)
    if (itemStart != value.Length || splitOptions == StringSplitOptions.None)
    {
        splitValues.Add(value.Substring(itemStart, value.Length - itemStart));
    }

    return splitValues.ToArray();
}

Ответ 5

result = originalString.Split(separator);
for(int i = 0; i < result.Length - 1; i++)
    result[i] += separator;

( РЕДАКТИРОВАТЬ - это плохой ответ - я неправильно понял его вопрос и не видел, чтобы он разбивал несколько символов.)

(EDIT - правильная версия LINQ неудобна, поскольку разделитель не должен конкатенироваться с последней строкой в ​​массиве split.)

Ответ 6

Недавно я написал метод расширения для этого:

public static class StringExtensions
    {
        public static IEnumerable<string> SplitAndKeep(this string s, string seperator)
        {
            string[] obj = s.Split(new string[] { seperator }, StringSplitOptions.None);

            for (int i = 0; i < obj.Length; i++)
            {
                string result = i == obj.Length - 1 ? obj[i] : obj[i] + seperator;
                yield return result;
            }
        }
    }

Ответ 7

Итерации по символу строки по символу (это то, что все равно регулярное выражение). Когда вы найдете сплиттер, затем отпустите подстроку.

псевдокод

int hold, counter;
List<String> afterSplit;
string toSplit

for(hold = 0, counter = 0; counter < toSplit.Length; counter++)
{
   if(toSplit[counter] = /*split charaters*/)
   {
      afterSplit.Add(toSplit.Substring(hold, counter));
      hold = counter;
   }
}

Такой тип С#, но не совсем. Очевидно, выберите подходящие имена функций. Кроме того, я думаю, что там может быть ошибка "вне игры".

Но это будет делать то, что вы просите.

Ответ 8

Много ответов на это! Один я постучал, чтобы разбить по различным строкам (исходный ответ удовлетворяет только символам, то есть длине 1). Это не было полностью протестировано.

public static IEnumerable<string> SplitAndKeep(string s, params string[] delims)
{
    var rows = new List<string>() { s };
    foreach (string delim in delims)//delimiter counter
    {
        for (int i = 0; i < rows.Count; i++)//row counter
        {
            int index = rows[i].IndexOf(delim);
            if (index > -1
                && rows[i].Length > index + 1)
            {
                string leftPart = rows[i].Substring(0, index + delim.Length);
                string rightPart = rows[i].Substring(index + delim.Length);
                rows[i] = leftPart;
                rows.Insert(i + 1, rightPart);
            }
        }
    }
    return rows;
}

Ответ 9

Regex.Split выглядит так, как будто он может делать то, что вы хотите, возможно.

Ответ 10

using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = @"This;is:a.test";
            char sep0 = ';', sep1 = ':', sep2 = '.';
            string pattern = string.Format("[{0}{1}{2}]|[^{0}{1}{2}]+", sep0, sep1, sep2);
            Regex regex = new Regex(pattern);
            MatchCollection matches = regex.Matches(input);
            List<string> parts=new List<string>();
            foreach (Match match in matches)
            {
                parts.Add(match.ToString());
            }
        }
    }
}

Ответ 11

Код Java:

public static class String_Ext
{
    public static string[] SplitOnGroups(this string str, string pattern)
    {
        var matches = Regex.Matches(str, pattern);
        var partsList = new List<string>();
        for (var i = 0; i < matches.Count; i++)
        {
            var groups = matches[i].Groups;
            for (var j = 0; j < groups.Count; j++)
            {
                var group = groups[j];
                partsList.Add(group.Value);
            }
        }
        return partsList.ToArray();
    }
}

var parts = "abcde  \tfgh\tikj\r\nlmno".SplitOnGroups(@"\s+|\S+");

for (var i = 0; i < parts.Length; i++)
    Print(i + "|" + Translate(parts[i]) + "|");

Вывод:

0|abcde|
1|  \t|
2|fgh|
3|\t|
4|ikj|
5|\r\n|
6|lmno|

Ответ 12

См. Использовать Regex.Split(). Я думаю, u/veggerby ответ лучший. Обратите внимание, что он использует синтаксис группы регулярных выражений (например, '(' и ')'), окружающий сопоставленные разделители, чтобы сохранить их в возвращаемом split.