【问题标题】:How to get parentheses inside parentheses如何在括号内获取括号
【发布时间】:2018-02-23 23:57:00
【问题描述】:

我试图在一个被括号包围的字符串中保留一个括号。

有问题的字符串是: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)

【问题讨论】:

  • 没有外括号怎么办?
  • @NetMage 然后它什么也不做。
  • 我的意思是,有没有可能输入的字符串不会被括号括起来,如果发生这种情况,应该如何处理?
  • @NetMage 如果输入字符串本身没有任何括号,它将跳过它。字符串不会被括号包围,而是我想在字符串中捕获括号。如果字符串被括号包围,那么它会通过括号,但只有当第一个用逗号与其余单词隔开的单词是颜色时才会通过。
  • 你好像又在自相矛盾了。您特别不想捕获字符串中的括号,否则您将拥有(orange, (hmm))。你的两个例子也是矛盾的——你怎么得到blue(hmm) derporange,(hmm)red,hmmm?但这开始看起来像是一个 XY 问题——你真正想要完成什么?

标签: c# regex


【解决方案1】:

你可以使用方法

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[]{',', ' '}, 

【讨论】:

  • 如果列表中的第一个或最后一个项目有括号,这将失败,例如((green), eggs, ham).
  • 问题是他的输入行的准确语法没有指定。
【解决方案2】:

这里发生了很多猜测——来自我和其他人。你可以试试

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

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

Here at regexstorm.

Visual illustration at regex101.

如果这激起了你的兴趣,我会添加一个解释;)

编辑:

如果您需要使用拆分,请将所选内容放入一个组中,例如

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

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

编辑 2:

不太确定你想要多级括号的行为,但我认为这可以为你做到:

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

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

See it here at ideone.

【讨论】:

  • 我现在修改了ideone example(来自已删除的评论)以使用拆分。见编辑。
  • 我不明白你从哪里得到它“忽略空格”。你检查过ideone example吗?它不会删除/忽略任何空格。
  • 啊。在之间,是的。这是故意的,因为我认为这是您想要的行为。好吧,我已经改变了它,现在它保留了它。查看修改。
  • 编辑并添加了另一个级别的递归
【解决方案3】:

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

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

【讨论】:

  • 这不适用于以下输入:herpdediderp (orange,(hmm)) some other crap (red,hmm)
  • @7h3w1z4rd 你对这个例子有什么期望?请将其添加到您的问题中。
【解决方案4】:

我认为,如果你倒过来考虑问题,它会变得更容易一些 - 不要分裂你不想要的东西,提取你想要的东西。

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

第一个例子:

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" }

【讨论】:

  • 为了澄清我的问题(即将编辑 TM),我想忽略第一层括号内的任何括号,因为它们在代码中无关紧要。我只是不希望它在应该拆分到其他括号时拆分到内括号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 2011-09-25
  • 2020-11-17
  • 2018-12-28
相关资源
最近更新 更多