Эффективно разбить строку в формате "{{}, {}, ...}" - PullRequest
3 голосов
/ 26 сентября 2019

У меня есть string в следующем формате.

string instance = "{112,This is the first day 23/12/2009},{132,This is the second day 24/12/2009}"

private void parsestring(string input)
{
    string[] tokens = input.Split(','); // I thought this would split on the , seperating the {}
    foreach (string item in tokens)     // but that doesn't seem to be what it is doing
    {
       Console.WriteLine(item); 
    }
}

Мой желаемый вывод должен выглядеть примерно так:

112,This is the first day 23/12/2009
132,This is the second day 24/12/2009

Но в настоящее время я получаю следующий:

{112
This is the first day 23/12/2009
{132
This is the second day 24/12/2009

Я очень плохо знаком с C #, и любая помощь будет признательна.

Ответы [ 5 ]

6 голосов
/ 26 сентября 2019

Не зацикливайтесь на Split (), который является решением!Это просто разобрать без него.Ответы на регулярные выражения, вероятно, тоже в порядке, но я думаю, что с точки зрения необработанной эффективности создание "парсера" могло бы сработать.

IEnumerable<string> Parse(string input)
{
    var results = new List<string>();
    int startIndex = 0;            
    int currentIndex = 0;

    while (currentIndex < input.Length)
    {
        var currentChar = input[currentIndex];
        if (currentChar == '{')
        {
            startIndex = currentIndex + 1;
        }
        else if (currentChar == '}')
        {
            int endIndex = currentIndex - 1;
            int length = endIndex - startIndex + 1;
            results.Add(input.Substring(startIndex, length));
        }

        currentIndex++;
    }

    return results;
}

Так что это не коротко.Он повторяется один раз и выполняет только одно распределение на «результат».С небольшими изменениями я мог бы сделать C # 8-версию с индексными типами, которая сокращает распределение?Это, вероятно, достаточно хорошо.

Вы могли бы потратить целый день на то, чтобы понять, как понимать регулярное выражение, но это так просто:

  • Сканирование каждого символа.
  • Если вы найдете {, обратите внимание, что следующий символ является началом результата.
  • Если вы найдете }, рассмотрите все от последнего отмеченного «начала» до индекса перед этим символом.как "результат".

Это не приведет к несовпадению скобок и может вызвать исключения для строк, таких как "}} {".Вы не просили обработать эти случаи, но не слишком сложно улучшить эту логику, чтобы поймать ее и кричать об этом или восстанавливаться.

Например, вы можете сбросить startIndex на что-то вроде -1, когда} найдено.Отсюда вы можете сделать вывод, если найдете { когда startIndex! = -1 вы нашли "{{".И вы можете сделать вывод, если вы найдете } когда startIndex == -1, вы нашли "}}".И если вы выйдете из цикла с startIndex <-1, это открытие <code>{ без закрытия }.это оставляет строку "} whoops" как непокрытый случай, но ее можно обработать, инициализируя startIndex, скажем, -2 и проверяя это специально.Сделайте это с регулярным выражением, и у вас будет болеть голова.

Основная причина, по которой я предлагаю это, - вы сказали "эффективно".Решение IcePickle хорошо, но Split() делает одно распределение для каждого токена, затем вы выполняете распределение для каждого вызова TrimX().Это не "эффективно".Это "n + 2 распределения".

5 голосов
/ 26 сентября 2019

Используйте Regex для этого:

string[] tokens = Regex.Split(input, @"}\s*,\s*{")
  .Select(i => i.Replace("{", "").Replace("}", ""))
  .ToArray();

Объяснение шаблона:

\s* - совпадать с нулем или более пробелами

4 голосов
/ 26 сентября 2019

Что ж, если у вас есть метод, который называется ParseString, хорошо, что он что-то возвращает (и, возможно, не так уж и плохо говорить, что вместо него ParseTokens).Поэтому, если вы сделаете это, вы можете перейти к следующему коду

private static IEnumerable<string> ParseTokens(string input)
{
    return input
        // removes the leading {
        .TrimStart('{')
        // removes the trailing }
        .TrimEnd('}')
        // splits on the different token in the middle
        .Split( new string[] { "},{" }, StringSplitOptions.None );
}

Причина, по которой он не работал у вас раньше, заключается в том, что ваше понимание того, как работает метод split, было неверным, оно будетэффективно разделить на все , в вашем примере.

Теперь, если вы сложите все это вместе, вы получите что-то вроде этого dotnetfiddle

using System;
using System.Collections.Generic;

public class Program
{
    private static IEnumerable<string> ParseTokens(string input)
    {
        return input
            // removes the leading {
            .TrimStart('{')
            // removes the trailing }
            .TrimEnd('}')
            // splits on the different token in the middle
            .Split( new string[] { "},{" }, StringSplitOptions.None );
    }

    public static void Main()
    {
        var instance = "{112,This is the first day 23/12/2009},{132,This is the second day 24/12/2009}";
        foreach (var item in ParseTokens( instance ) ) {
            Console.WriteLine( item );
        }
    }
}
1 голос
/ 26 сентября 2019

Если вы не хотите использовать регулярные выражения, следующий код выдаст требуемый вывод.

        string instance = "{112,This is the first day 23/12/2009},{132,This is the second day 24/12/2009}";

        string[] tokens = instance.Replace("},{", "}{").Split('}', '{');
        foreach (string item in tokens)
        {
            if (string.IsNullOrWhiteSpace(item)) continue;

            Console.WriteLine(item);
        }

        Console.ReadLine();
1 голос
/ 26 сентября 2019

Добавьте using System.Text.RegularExpressions; к вершине класса

и используйте метод разделения регулярных выражений

string[] tokens = Regex.Split(input, "(?<=}),");

Здесь мы используем положительный прогноз, чтобы разделить на ,, который идет сразу после}

(примечание: (?<= ваша строка ) соответствует всем символам после вашей строки. Подробнее об этом можно прочитать здесь

...