1

当我只有一个平衡角色时,我已经通过平衡 Regex 来做到这一点......但是有了更多平衡角色,它变得更加复杂和丑陋。

就我目前的目的而言,我改为编写了一个方法来通过对字符串进行标记来做到这一点,但它非常慢(而且效率非常低)。最昂贵的部分似乎是我正在做的无偿使用子字符串(是的,我知道这很糟糕)。

基本上,我想采取以下

  hello("(abc d)", efg (hijk)) and,some more<%lmn, "o(\")pq", (xy(z))%>

最后得到

hello("(abc d)", efg (hijk)) 
[space] (the actual character)
and
,
some more
<%lmn, "o()pq", (xy(z))%>

换句话说,我正在拆分(我希望这些包含在数组结果中)

[space]
,

....我有“平衡的分组字符串”

" "
( )
<% %> 

...而且我有转义字符

\

我不想为此目的编写一个完整的大解析器......

这是代码:

    public static IEnumerable<string> SplitNotEnclosed(this string s, IEnumerable<string> separators, Dictionary<string, string> enclosingValues = null, IEnumerable<char> escapeCharacters = null, bool includeSeparators = false, StringComparison comparisonType = StringComparison.Ordinal)
    {
        var results = new List<string>();

        var enclosureStack = new Stack<KeyValuePair<string, string>>();
        bool atEscapedCharacter = false;

        if (escapeCharacters == null) escapeCharacters = new[] { '\\' };
        if (enclosingValues == null) enclosingValues = new[] { "\"" }.ToDictionary(i => i);

        var orderedEnclosingValues = enclosingValues.OrderByDescending(i => i.Key.Length).ToArray();
        separators = separators.OrderByDescending(v => v.Length).ToArray();

        var currentPart = new StringBuilder();

        while (s.Length > 0)
        {
            int addToIndex = 0;

            var newEnclosingValue = orderedEnclosingValues.FirstOrDefault(v => s.StartsWith(v.Key, comparisonType));

            if (enclosureStack.Count > 0 && !atEscapedCharacter && s.StartsWith(enclosureStack.Peek().Value))
            {
                addToIndex = enclosureStack.Peek().Value.Length;
                enclosureStack.Pop();
            }
            else if (newEnclosingValue.Key != null && !atEscapedCharacter)
            {
                enclosureStack.Push(newEnclosingValue);
                addToIndex = newEnclosingValue.Key.Length;
            }
            else if (escapeCharacters.Contains(s[0]) && enclosureStack.Count > 0)
            {
                atEscapedCharacter = !atEscapedCharacter;
                addToIndex = 1;
            }
            else if (enclosureStack.Count > 0)
            {
                atEscapedCharacter = false;
                addToIndex = 1;
            }

            if (enclosureStack.Count == 0)
            {
                string separator = separators.FirstOrDefault(v => s.StartsWith(v, comparisonType));

                if (separator != null)
                {
                    if (currentPart.Length > 0) results.Add(currentPart.ToString());
                    results.Add(separator);
                    s = s.Substring(separator.Length);
                    currentPart = new StringBuilder();

                    addToIndex = 0;
                }
                else
                {
                    addToIndex = 1;
                }
            }

            currentPart.Append(s.Substring(0, addToIndex));
            s = s.Substring(addToIndex);
        }

        if (currentPart.Length > 0) results.Add(currentPart.ToString());

        if (!includeSeparators)
        {
            results = results.Except(separators).ToList();
        }

        return results.ToArray();
    }
4

0 回答 0