【问题标题】:Removing White Space: C#删除空格:C#
【发布时间】:2013-08-28 17:12:20
【问题描述】:

我正在尝试存在于String input 中的remove white space。我的最终目标是创建一个中缀求值器,但我在解析输入表达式时遇到了问题。

在我看来,解决这个问题的简单方法是使用Regular Expression 函数,即Regex.Replace(...)

这是我到目前为止所拥有的......

infixExp = Regex.Replace(infixExp, "\\s+", string.Empty);
string[] substrings = Regex.Split(infixExp, "(\\()|(\\))|(-)|(\\+)|(\\*)|(/)");

假设用户输入中缀表达式 (2 + 3) * 4,我希望这会将字符串分解为数组 {(, 2, +, 3, ), *, 4};但是,调试后,我得到以下输出:

infixExp = "(2+3)*7"
substrings = {"", (, 2, +, 3, ), "", *, 7}

似乎已从中缀表达式中正确删除了空格,但拆分结果字符串是不正确的。

谁能告诉我为什么?同样,如果您有任何建设性的批评或建议,请告诉我!

【问题讨论】:

  • 正则表达式不适合解析嵌套结构...
  • It appears that the white space is being properly removed from the infix expression 如果是这样,那你为什么要谈论删除空格?
  • @leppie:对我来说,正则表达式的唯一目的似乎是对输入进行标记。嵌套结构的解析稍后会根据标记进行。如果确实如此,那么使用正则表达式进行标记应该可以工作。
  • @leppie .NET 实际上有一些非常优雅的正则表达式结构可以做到这一点。但是,OP 似乎并没有解析嵌套结构,而只是将字符串拆分为单独的标记......我认为正则表达式非常适合。
  • 如果不是作业或学习目的,我会说使用NCalc

标签: c# .net regex whitespace infix-notation


【解决方案1】:

如果匹配项位于字符串的一端,您将在其旁边获得一个空匹配项。同样,如果有两个相邻的匹配项,则字符串将在两个匹配项上拆分,因此您最终会得到一个空字符串。引用MSDN

如果多个匹配项彼此相邻,则将一个空字符串插入到数组中。例如,将字符串拆分为单个连字符会导致返回的数组在找到两个相邻连字符的位置包含一个空字符串 [...]。

如果在输入字符串的开头或结尾找到匹配项,则在返回数组的开头或结尾包含一个空字符串。

只需在第二步中过滤掉它们。

另外,请让您的生活更轻松并使用逐字字符串:

infixExp = Regex.Replace(infixExp, @"\s+", string.Empty);
string[] substrings = Regex.Split(infixExp, @"(\(|\)|-|\+|\*|/)");

第二个表达式可以进一步简化:

@"([()+*/-])"

【讨论】:

    【解决方案2】:

    请放弃正则表达式。有更好的工具可以使用。您可以使用String.Trim().TrimEnd().TrimStart()

    string inputString = "   asdf    ";
    string output = inputString.Trim();
    

    对于字符串中的空格,使用String.Replace

    string output2 = output.Replace(" ", "");
    

    您必须将其扩展到其他空白字符。

    【讨论】:

    • 我仍然看不到使用多个纯字符串替换空格、制表符和换行符比简单的\s+ 有什么优势。
    • @m.buettner “优势”可能有点主观,但我明白你的意思。 IMO,Regex 不是这项工作的正确工具,但在孤立的情况下,它可以工作。
    【解决方案3】:
    var result = Regex.Split(input, "(\\d+|\\D)")
                  .Where(x=>x!="").ToArray();
    

    【讨论】:

    • 那会丢弃令牌,不是吗?
    • @m.buettner 令牌是什么?我认为他只是想将输入字符串(一个表达式)转换为一个包含除空格之外的所有字符的数组。
    • 我的意思是,您的结果不会包含运算符,对吧?它只会留下数字。
    • @m.buettner 你说得对,我没仔细看,看来我们这里要用Regex.Split,我更新了我的答案Regex
    【解决方案4】:

    m.buettner's answer 是正确的。还要考虑您可以一步完成。来自MSDN

    如果在 Regex.Split 表达式中使用捕获括号,则任何 捕获的文本包含在结果字符串数组中。

    因此,如果您在拆分模式中包含空格但在捕获括号之外,您也可以在其上拆分但不将其包含在结果数组中:

    var substrings = Regex.Split("(2 + 3) * 7", @"([()+*/-])|\s+");
    

    结果:

    substrings = {"", ( , 2, "", +, "", 3, ), "", "", *, "", 7}
    

    你的最终结果是:

    substrings.Where(s => s != String.Empty)
    

    【讨论】:

    • 非常整洁!但结果略有不同:在您的情况下,数字之间的空格会导致两个数字/令牌,而使用 OP 的两步方法只会导致一个数字/令牌。
    【解决方案5】:

    为什么不直接删除空格,然后使用普通字符串处理函数拆分字符串?像这样……

    string x = "(2 + 3) * 4";
    x = x.Replace(" ", "").Replace("\t",""); //etc...
    char[] y = x.ToCharArray();
    

    为什么要让事情变得比它需要的更复杂?

    【讨论】:

    • 我想将数字保存在一个令牌中很好。
    • ToCharArray 不起作用,因为它会撕开多于一位的数字。
    • @Jasmine:如何让多个Replace 调用而不是单个调用更具可读性?必须手动考虑所有可能的空格而不是使用标准化集合,这如何更可靠?
    • @Jasmine:我们一般不是在谈论正则表达式。我们正在谈论 Regex.Replace(infixExp, @"\s+", string.Empty);x = x.Replace(" ", "").Replace("\t",""); //etc...
    • @DanielHilgarth 附议。 Jasmine,您的论点暗示永远不应该使用正则表达式,因为存在滥用它们的危险。在这种特殊情况下,正则表达式提供了一种非常简洁、易读和优雅的解决方案,并且可能比进行四次替换(如果输入可以包含任意 Unicode,则实际上是几十次)更快。
    【解决方案6】:

    非正则表达式解决方案可能是String.Replace - 您可以简单地将“”、“\t”和其他空格替换为空字符串“”。

    【讨论】:

    • 这比用空字符串正则表达式替换\s 更简单吗?
    • 我必须承认我没有合适的答案。重读我的问题后,它似乎确实不够。我很抱歉。
    【解决方案7】:

    感谢您的所有回复,我找到了我正在寻找的解决方案。

    // Ignore all whitespace within the expression.
    infixExp = Regex.Replace(infixExp, @"\s+", String.Empty);
    
    // Seperate the expression based on the tokens (, ), +, -, 
    // *, /, and ignore any of the empty Strings that are added
    // due to duplicates.
    string[] substrings = Regex.Split(infixExp, @"([()+*/-])");
    substrings = substrings.Where(s => s != String.Empty).ToArray();
    

    通过这样做,它根据常规数学运算符(+、-、*、/)和括号将字符串的字符分成几部分。完成此操作后,它会消除 substrings

    中的任何剩余空字符串

    【讨论】: