如何在括号内括起来

问题描述 投票:2回答:4

我试图将一个括号保留在一个被括号括起来的字符串中。

有问题的字符串是:test (blue,(hmmm) derp)

数组的所需输出是:test(blue,(hmmm) derp)

目前的输出是:(blue,(hmm)derp)

我目前的代码是this

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

如何在外部括号中提取文本(保留它们)并将内部括号保留为数组中的一个字符串?

编辑:

为了澄清我的问题,我想忽略内括号,只在外括号上拆分。

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

应该成为:

herpdediderporange,(hmm)some other crapred,hmm

该代码适用于除双括号外的所有内容:(orange,(hmm))orange,(hmm)

c# regex
4个回答
2
投票

很多人在这里猜测 - 来自我和其他人。你可以试试

[^(]+|\([^(]*(?:\([^(]*\)[^(]*)*\)

它处理一个级别的括号递归(虽然可以扩展)。

Here at regexstorm

Visual illustration at regex101

如果这引起你的兴趣,我会加上一个解释;)

编辑:

如果您需要使用拆分,请将选择放入组中,例如

([^(]+|\([^(]*(?:\([^(]*\)[^(]*)*\))

并过滤掉空字符串。参见示例here at ideone

编辑2:

不太确定你需要多个级别的括号,但我认为这可以为你做:

([^(]+|\([^(]*(?:\([^(]*(?:\([^(]*\)[^(]*)*\)[^(]*)*\))
                        ^^^^^^^^^^^^^^^^^^^ added

对于您想要的每个级别的递归,您只需“添加”另一个内部级别。所以这是两个级别的递归;)

See it here at ideone


4
投票

您可以使用该方法

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

如果该行可以以2个连续的括号开头或结尾,请使用简单的旧if语句:

if (line.StartsWith("(")) {
    line = line.Substring(1);
}
if (line.EndsWith(")")) {
    line = line.Substring(0, line.Length - 1);
}
string[] input = line.Split(new[]{',', ' '}, 

1
投票

希望有人会想出一个正则表达式。这是我的代码答案。

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

Code on DotNetFiddle


0
投票

我认为如果你向后看这个问题,它会变得容易一点 - 不要分解你不做什么,提取你想要的东西。

如果匹配嵌套括号,唯一有点棘手的部分,我假设你只会深入一级。

第一个例子:

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" }
© www.soinside.com 2019 - 2024. All rights reserved.