我试图将一个括号保留在一个被括号括起来的字符串中。
有问题的字符串是: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)
应该成为:
herpdediderp
,orange,(hmm)
,some other crap
和red,hmm
。
该代码适用于除双括号外的所有内容:(orange,(hmm))
到orange,(hmm)
。
很多人在这里猜测 - 来自我和其他人。你可以试试
[^(]+|\([^(]*(?:\([^(]*\)[^(]*)*\)
它处理一个级别的括号递归(虽然可以扩展)。
Visual illustration at regex101。
如果这引起你的兴趣,我会加上一个解释;)
编辑:
如果您需要使用拆分,请将选择放入组中,例如
([^(]+|\([^(]*(?:\([^(]*\)[^(]*)*\))
并过滤掉空字符串。参见示例here at ideone。
编辑2:
不太确定你需要多个级别的括号,但我认为这可以为你做:
([^(]+|\([^(]*(?:\([^(]*(?:\([^(]*\)[^(]*)*\)[^(]*)*\))
^^^^^^^^^^^^^^^^^^^ added
对于您想要的每个级别的递归,您只需“添加”另一个内部级别。所以这是两个级别的递归;)
您可以使用该方法
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[]{',', ' '},
希望有人会想出一个正则表达式。这是我的代码答案。
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
我认为如果你向后看这个问题,它会变得容易一点 - 不要分解你不做什么,提取你想要的东西。
如果匹配嵌套括号,唯一有点棘手的部分,我假设你只会深入一级。
第一个例子:
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" }