如何仅在整个文本被括号包围时删除括号?

3
我希望只有当整个文本被括号包围时才删除括号。例如:
(text (text) text)

需要转换为:

text (text) text

我有一个非常简单的检查:

value = (value [0] == '(' && value [value .Length - 1] == ')') ? value.Substring(1, value .Length - 2) : value;

但它失败了,错误地去除了这种字符串的括号:
(text (text) ) text (text)

你能告诉我一个处理所有情况的方法吗?使用正则表达式也是可以的。

请注意,括号必须平衡。例如,下面这种情况是不可能的:

( text ( text )

在你的失败案例中,“整个文本”没有被括号包围,这显然是你想要解决的问题,你能重新陈述一下你试图解决的问题吗? - Daniel Hoffmann-Mitscherling
你的示例中的 text 可以包含空格吗? - Pruthvi Raj
1
正则表达式不适用于此。它缺乏解析和“记忆”上下文的能力。但使用循环实现相当简单。 - Amit
你还有 (文本(文本)) (文本(文本))。我认为你最好能做的是用 foreach(char c in string) 循环遍历每个字符,将每个开括号映射到一个闭括号,最后一个括号会与第一个括号匹配或不匹配。 - paparazzo
3个回答

4

使用简单的循环进行测试,如果可以“有效”删除,则先删除第一个和最后一个:

bool isValid = value[0] == '(' && value[value.Length - 1] == ')';
int i = 1;
int c = 0;
for(; isValid && c >= 0 && i < value.Length - 1; i++)
{
  if(value[i] == '(')
    c++;
  else if(value[i] == ')')
    c--;
}

if(isValid && i == (value.Length - 1) && c == 0)
  value = value.Substring(1, value.Length - 2);

现在更错了。ic都应该从0开始。另外,当c等于0时,必须中断循环(在循环结束时检查c == 0)。 - M.kazem Akhgary
@M.kazemAkhgary - 不应该这样做... i = 0 已经被验证过了,正如 Eric 刚刚建议的那样,甚至可以通过检查最后一个字符来改进它。 - Amit
@M.kazemAkhgary:我不理解你的评论;第一个字符已经通过在“isValid”的初始化中进行检查而被处理。如果它是真的,那么就有一个字符被处理了,计数器是一个开放括号。此外,代码确实检查c是否等于零,在循环条件中。它是一个非负数,因此检查它是否大于零就足够了。 - Eric Lippert
现在这个已经可以工作了。但是如果你从1开始c并且在c等于0时跳出循环,会更好一些。那样更有意义。 - M.kazem Akhgary
@M.kazemAkhgary - 我认为这样或那样都没有太多意义。它只是应该简单而有效。无论计数是针对所有括号还是仅限于外部括号内的括号(因此负数是非法的)都没有区别。 - Amit

1
这个扩展方法应该可以工作;
public static class StringExtensions
{
    public static string RemoveParentheses(this string value)
    {
        if (value == null || value[0] != '(' || value[value.Length - 1 ] != ')') return value;

        var cantrim = false;
        var openparenthesesIndex = new Stack<int>();
        var count = 0;
        foreach (char c in value)
        {
            if (c == '(')
            {
                openparenthesesIndex.Push(count);
            }
            if (c == ')')
            {
                cantrim = (count == value.Length - 1 && openparenthesesIndex.Count == 1 && openparenthesesIndex.Peek() == 0);
                openparenthesesIndex.Pop();
            }
            count++;
        }

        if (cantrim)
        {
            return value.Trim(new[] { '(', ')' });
        }
        return value;
    }
}

使用方式如下:
Console.WriteLine("(text (text) ) text (text)".RemoveParentheses());

1
运行了几个测试用例,我认为这很好。
public string CleanString(string CleanMe)
{
    if (string.IsNullOrEmpty(CleanMe)) return CleanMe;
    string input = CleanMe.Trim();
    if (input.Length <= 2) return input;
    if (input[0] != '(') return input;
    if (input[input.Length-1] != ')') return input;
    int netParen = 1;  // starting loop at 1 have one paren already
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i < input.Length-1; i++)
    {
        char c = input[i];
        sb.Append(c);
        if (c == '(') netParen++;
        else if (c == ')') netParen--;
        if (netParen == 0) return input;  // this is the key did the () get closed out
    }
    return sb.ToString();
}

在阿米特的回答之前,我就开始了这个项目,但我认为它的基本逻辑是相同的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接