C# 如何简化此方法(拆分不带引号、不带括号、不带换行符的逗号)?

C# 如何简化此方法(拆分不带引号、不带括号、不带换行符的逗号)?,c#,parsing,C#,Parsing,好奇这是否可以简化 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.L

好奇这是否可以简化

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);
}
预期产出:

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

要保持你的自动机状态有点尴尬。在这种情况下,我将使用单个变量或堆栈。因此,您当前的状态始终为stateStack.Peek。容易阅读。易于处理嵌套状态

编辑:这里有一个简单的例子。我相信您可以扩展它来添加错误处理和规则的细节

    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);
    }

要保持你的自动机状态有点尴尬。在这种情况下,我将使用单个变量或堆栈。因此,您当前的状态始终为stateStack.Peek。容易阅读。易于处理嵌套状态

编辑:这里有一个简单的例子。我相信您可以扩展它来添加错误处理和规则的细节

    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);
    }

您是否考虑过regex?您所生成的代码可能不是最简洁或最优雅的,但它是可维护的——在我看来,这是代码最重要的一点。此代码是否导致任何问题?如果不是的话,我就不去管它了。@Jimplade:是的,我相信这将是一个可怕的方法,如果它是可行的话@克丽丝芙:在我的测试中似乎很有效。我不太担心优化它,只是想知道它是否可以进一步简化。。。它有一些代码冗余之类的问题。@jimplate:因为它不容易读、写和维护?是的,这是一个糟糕的方法。我也不知道如何在几个正则表达式中实现这一点。。除非你想用正则表达式替换掉不相关的部分,然后在剩下的部分做一个简单的字符串分割,但是。。。我看不出这有多好。jimplode:我很想看到一个执行此任务的正则表达式!无论如何,发布一个,我会投票赞成。你有没有考虑过regex?你所产生的代码,虽然可能不是最简洁或优雅的,但它是可维护的——在我看来,这是代码最重要的一点。此代码是否导致任何问题?如果不是的话,我就不去管它了。@Jimplade:是的,我相信这将是一个可怕的方法,如果它是可行的话@克丽丝芙:在我的测试中似乎很有效。我不太担心优化它,只是想知道它是否可以进一步简化。。。它有一些代码冗余之类的问题。@jimplate:因为它不容易读、写和维护?是的,这是一个糟糕的方法。我也不知道如何在几个正则表达式中实现这一点。。除非你想用正则表达式替换掉不相关的部分,然后在剩下的部分做一个简单的字符串分割,但是。。。我看不出这有多好。jimplode:我很想看到一个执行此任务的正则表达式!无论如何,发布一个,我会投票支持。然后把引号和[s]都推到上面?关于转义符呢?你会把它们推到上面吗?好吧,这对你来说更像是一个问题。你支持嵌套括号吗?如果支持,那么每次遇到['。如果没有,则推第一个字符,并将其他字符视为纯文本。括号和引号的组合也是如此。至于转义字符-是的,我会推这些字符。基本上你想要状态。Peek就是我现在所在的位置。因此,如果你遇到转义字符,那么你接下来的循环过程需要知道它。我也是一位同事nfused:您没有在输出上取消转义符?这是疏忽还是有意的?嗯…不确定…实际上还没有需要在实践中取消任何转义。我不知道这个方法是否应该处理取消转义,或者应该委托给实际使用此函数的方法。反正都是内部的。Peeo,Pop,Push,Subst戒指。它有点吸引人:把引号和[s]都推到上面?关于转义符呢?你会把它们也推到上面吗?好吧,这对你来说更是个问题。你支持嵌套括号吗?如果支持,那么每次遇到['。如果没有,则推第一个字符,并将其他字符视为纯文本。括号和引号的组合也是如此。至于转义字符-是的,我会推这些字符。基本上你想要状态。Peek就是我现在所在的位置。因此,如果你遇到转义字符,那么你接下来的循环过程需要知道它。我也是一位同事nfused:您没有在输出上取消转义符?这是疏忽还是有意的?嗯…不确定…实际上还没有需要在实践中取消任何转义。我不知道这个方法是否应该处理取消转义,或者应该委托给实际使用此函数的方法。反正都是内部的。Peeo,Pop,Push,Subst戒指。有点吸引人: