Как упростить этот метод (расщепление без кавычек, без скобок, без пробелов) - PullRequest
1 голос
/ 04 октября 2010

Интересно, можно ли это упростить ...

internal static IEnumerable<string> Split(string str, char sep = ',')
{
    int lastIndex = 0;
    bool quoted = false;
    bool escaped = false;
    bool bracketed = false;
    char lastQuote = '\0';

    for (int i = 0; i < str.Length; ++i)
    {
        if (str[i] == '[')
        {
            if (!quoted && !escaped)
                bracketed = true;
            escaped = false;
        }
        else if (str[i] == ']')
        {
            if (!quoted && !escaped)
                bracketed = false;
            escaped = false;
        }
        else if (str[i] == '\\')
        {
            escaped = !escaped;
        }
        else if (str[i] == '"' || str[i] == '\'')
        {
            if (!escaped)
            {
                if (quoted)
                {
                    if (lastQuote == str[i])
                        quoted = false;
                }
                else
                {
                    quoted = true;
                    lastQuote = str[i];
                }
            }
            escaped = false;
        }
        else if (str[i] == sep)
        {
            if (!quoted && !escaped && !bracketed)
            {
                yield return str.Substring(lastIndex, i - lastIndex);
                lastIndex = i + 1;
            }
            escaped = false;
        }
        else
        {
            escaped = false;
        }
    }

    yield return str.Substring(lastIndex);
}

Написал этот метод для разделения на запятые, которые не находятся внутри [], не заключены в кавычки и не экранированы. Это сложная проблема, или я выбрал глупый подход?

Введите:

foreach(var sel in SharpQuery.SplitCommas("\"comma, in quotes\", comma[in,brackets], comma[in \"quotes, and brackets\"], \"woah, 'nelly,' \\\"now you,re [talking, crazy\\\"\"")) {
    Console.WriteLine(sel);
}

Ожидаемый результат:

"comma, in quotes"
 comma[in,brackets]
 comma[in "quotes, and brackets"]
 "woah, 'nelly,' \"now you,re [talking, crazy\""

1 Ответ

6 голосов
/ 04 октября 2010

Немного неуклюжий выбор для поддержания вашего состояния автомата. Я бы использовал одну переменную или стек в этом случае. Таким образом, ваше текущее состояние всегда stateStack.Peek(). Легко читать. Легко обрабатывать вложенные состояния.

edit: вот быстрый пример. Я уверен, что вы можете расширить его, добавив обработку ошибок и особенности ваших правил.

    enum ParserState
    {
        Text,
        Bracketed,
        Quoted,
        EscapChar,
    }

    internal static IEnumerable<string> Split(string str, char sep)
    {
        int lastIdx = 0;
        char c;
        ParserState s;
        Stack<ParserState> state = new Stack<ParserState>();
        state.Push(ParserState.Text);

        for (int i = 0; i < str.Length; i++)
        {
            c = str[i];
            s = state.Peek();

            if (s == ParserState.EscapChar
                || (s == ParserState.Bracketed && c == ']')
                || (s == ParserState.Quoted && c == '"'))
            {
                state.Pop();
            }
            else if (c == '[')
                state.Push(ParserState.Bracketed);
            else if (c == '"')
                state.Push(ParserState.Quoted);
            else if (c == '\\')
                state.Push(ParserState.EscapChar);
            else if (s == ParserState.Text && c == sep)
            {
                yield return str.Substring(lastIdx, i - lastIdx);
                lastIdx = i + 1;
            }
        }
        yield return str.Substring(lastIdx);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...