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

Рассматриваемая строка: test (blue,(hmmm) derp)

Желаемый вывод в массив: test и (blue,(hmmm) derp).

Текущий вывод: (blue,, (hmm) и derp).

Мой текущий код - это этот:

var input = Regex
  .Split(line, @"(\([^()]*\))")
  .Where(s => !string.IsNullOrEmpty(s))
  .ToList();

Как я могу извлечь текст внутри внешних скобок (сохраняя их) и сохранить внутренние скобки как одну строку в массиве?

< Сильный > EDIT :

Чтобы прояснить мой вопрос, я хочу игнорировать внутренние скобки и разделять только на внешние скобки.

herpdediderp (orange,(hmm)) some other crap (red,hmm)

Должно стать:

herpdediderp, orange,(hmm), some other crap и red,hmm.

Код работает для всего, кроме двойных скобок: от (orange,(hmm)) до orange,(hmm).

2
7h3w1z4rd 24 Фев 2018 в 02:57

3 ответа

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

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

Первый пример:

var s1 = "(blue, (hmmm) derp)";
var input = Regex.Matches(s1, @"\((?:\(.+?\)|[^()]+)+\)").Cast<Match>().Select(m => Regex.Matches(m.Value, @"\(\w+\)|\w+").Cast<Match>().Select(m2 => m2.Value).ToArray()).ToArray();
// input is string[][] { string[] { "blue", "(hmmm)", "derp" } }

Во втором примере используется метод расширения:

public static string TrimOutside(this string src, string openDelims, string closeDelims) {
    if (!String.IsNullOrEmpty(src)) {
        var openIndex = openDelims.IndexOf(src[0]);
        if (openIndex >= 0 && src.EndsWith(closeDelims.Substring(openIndex, 1)))
            src = src.Substring(1, src.Length - 2);
    }
    return src;
}

Код / шаблоны отличаются, потому что два примера обрабатываются по-разному:

var s2 = "herpdediderp (orange,(hmm)) some other crap (red,hmm)";
var input3 = Regex.Matches(s2, @"\w(?:\w| )+\w|\((?:[^(]+|\([^)]+\))+\)").Cast<Match>().Select(m => m.Value.TrimOutside("(",")")).ToArray();
// input2 is string[] { "herpdediderp", "orange,(hmm)", "some other crap", "red,hmm" }
0
NetMage 27 Фев 2018 в 18:50

Надеюсь, кто-нибудь придумает регулярное выражение. Вот мой код ответа.

static class ExtensionMethods
{
    static public IEnumerable<string> GetStuffInsideParentheses(this IEnumerable<char> input)
    {
        int levels = 0;
        var current = new Queue<char>();
        foreach (char c in input)
        {
            if (levels == 0)
            {
                if (c == '(') levels++;
                continue;
            }
            if (c == ')')
            {
                levels--; 
                if (levels == 0)
                { 
                    yield return new string(current.ToArray()); 
                    current.Clear();
                    continue;
                }
            }
            if (c == '(')
            {
                levels++; 
            }
            current.Enqueue(c); 
        }
    }
}

Тестовая программа:

public class Program
{
    public static void Main()
    {

        var input = new []
        {
            "(blue,(hmmm) derp)", 
            "herpdediderp (orange,(hmm)) some other crap (red,hmm)"
        };

        foreach ( var s in input )
        {
            var output = s.GetStuffInsideParentheses();
            foreach ( var o in output )
            {
                Console.WriteLine(o);
            }
            Console.WriteLine();
        }
    }
}

Выход:

blue,(hmmm) derp

orange,(hmm)
red,hmm

Код на DotNetFiddle

1
John Wu 24 Фев 2018 в 19:18

Вы можете использовать метод

public string Trim(params char[] trimChars)

Нравится

string trimmedLine = line.Trim('(', ')'); // Specify undesired leading and trailing chars.

// Specify separator characters for the split (here command and space):
string[] input = trimmedLine.Split(new[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);

Если строка может начинаться или заканчиваться двумя последовательными скобками, используйте просто старые добрые операторы if:

if (line.StartsWith("(")) {
    line = line.Substring(1);
}
if (line.EndsWith(")")) {
    line = line.Substring(0, line.Length - 1);
}
string[] input = line.Split(new[]{',', ' '}, 
4
Olivier Jacot-Descombes 24 Фев 2018 в 15:00