替换单个WhiteSpace而无需替换多个WhiteSpace

时间:2016-02-15 15:18:26

标签: c# whitespace

我有一个格式的字符串: abc def ghi xyz

我想以格式结束: abcdefghi xyz

最好的方法是什么?在这种特殊情况下,我可以删除最后三个字符,删除空格,然后在最后添加它们,但这对于多个空格位于字符串中间的情况不起作用。

简而言之,我想删除所有单个空格,然后用一个空格替换所有多个空格。这些步骤中的每一步本身都很容易,但将它们组合起来似乎不那么简单。

我愿意使用正则表达式,但我不愿意。

5 个答案:

答案 0 :(得分:4)

这种方法使用正则表达式,但希望以一种仍然相当可读的方式。首先,将输入字符串拆分为多个空格

var pattern = @"  +"; // match two or more spaces
var groups = Regex.Split(input, pattern);

接下来,从每个标记中删除(个别)空格:

var tokens = groups.Select(group => group.Replace(" ", String.Empty));

最后,使用单个空格加入您的令牌

var result = String.Join(' ', tokens.ToArray());

此示例使用文字空格字符而不是“空格”(包括制表符,换行符等) - 如果需要拆分多个空白字符而不是实际空格,则将\s替换为“。 / p>

答案 1 :(得分:2)

嗯,正则表达式在这里可能是最快的,但是你可以实现一些算法,它使用单个空格的前瞻,然后在循环中替换多个空格:

// Replace all single whitespaces
for (int i = 0; i < sourceString.Length; i++)
{
    if (sourceString[i] = ' ')
    {
        if (i < sourceString.Length - 1 && sourceString[i+1] != ' ')
          sourceString = sourceString.Delete(i);
    }
}

// Replace multiple whitespaces
while (sourceString.Contains("  ")) // Two spaces here!
  sourceString = sourceString.Replace("  ", " ");

但是,嘿,与正确的正则表达式相比,该代码相当丑陋和缓慢......

答案 2 :(得分:2)

对于非R​​EGEX选项,您可以使用:

string str = "abc def ghi         xyz";
var result = str.Split(); //This will remove single spaces from the result
StringBuilder sb = new StringBuilder();
bool ifMultipleSpacesFound = false;
for (int i = 0; i < result.Length;i++)
{
    if (!String.IsNullOrWhiteSpace(result[i]))
    {
        sb.Append(result[i]);
        ifMultipleSpacesFound = false;
    }
    else
    {
        if (!ifMultipleSpacesFound)
        {
            ifMultipleSpacesFound = true;
            sb.Append(" ");
        }
    }
}

string output = sb.ToString();

输出结果为:

output = "abcdefghi xyz"

答案 3 :(得分:1)

这是一种使用一些相当微妙的逻辑的方法:

public static string RemoveUnwantedSpaces(string text)
{
    var sb = new StringBuilder();
    char lhs = '\0';
    char mid = '\0';

    foreach (char rhs in text)
    {
        if (rhs != ' ' || (mid == ' ' && lhs != ' '))
            sb.Append(rhs);

        lhs = mid;
        mid = rhs;
    }

    return sb.ToString().Trim();
}

工作原理:

我们将在字符串中线性地检查每个可能的三字符子序列(在一种三字符滑动窗口中)。这三个字符将按顺序由变量lhsmidrhs表示。

对于字符串中的每个rhs字符:

  • 如果它不是空格,我们应该输出它。
  • 如果一个空格,而前一个字符也是空格但之前的字符不是,则这是序列中的第二个至少有两个空格,因此我们应该输出一个空格。
  • 否则,不要输出空格,因为这是两个或多个空格序列中的第一个或第三个(或更晚的)空格,在任何一种情况下我们都不想输出空格:如果这恰好是两个或多个空格序列中的第一个,则在第二个空格出现时将输出一个空格。如果这是第三个或更晚的,我们已经为它输出了一个空间。

这里的细微之处在于,我通过使用非空格字符初始化lhsmid变量来避免特殊包装序列的开头。这些值是什么并不重要,只要它们不是空格,但我将它们\0表示它们是特殊值。

答案 4 :(得分:1)

经过第二次思考,这里有一行regex solution

Regex.Replace("abc def ghi    xyz", "( )( )*([^ ])", "$2$3")

结果是"abcdefghi xyz"

原始答案:

两行代码正则表达式解决方案:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")

tmp "abcdefghi xyz" 然后:

var result = Regex.Replace(tmp, "( )+", " ");

result "abcdefghi xyz"

<强>解释

第一行代码删除单个空格并删除多个空格的一个空格(因此 tmp 中的字母 i X )。

第二行只是用一个空格替换多个空格。

第一行的深入解释:

我们将输入字符串与匹配一个空格的正则表达式匹配,并将其旁边的非空格匹配。我们还将这两个字符放在不同的组中(我们使用( )进行匿名分组)。 因此对于"abc def ghi xyz"字符串,我们有匹配和组:

匹配:" d" group1:" " group2:"d"

匹配:" g" group1:" " group2:"g"

匹配:" x" group1:" " group2:"x"

我们使用substitution syntax Regex.Replace方法将匹配替换为第二组内容(非空白字符)