C# 替换单个空格而不替换多个空格

C# 替换单个空格而不替换多个空格,c#,whitespace,C#,Whitespace,我有一个字符串,格式如下: abc def ghi xyz 我想以以下格式结束: abcdefghi xyz 最好的方法是什么?在这种特殊情况下,我可以删去最后三个字符,删除空格,然后在结尾添加它们,但是对于多个空间位于字符串中间的情况,这将不起作用。 简而言之,我想删除所有单个空格,然后用单个空格替换所有多个空格。这些步骤中的每一步本身都很简单,但将它们结合起来似乎不那么简单 我愿意使用正则表达式,但我不想使用。好吧,正则表达式可能是这里最快的,但您可以实现一些算法,对单个空间使用前瞻,然后在

我有一个字符串,格式如下:
abc def ghi xyz

我想以以下格式结束:
abcdefghi xyz

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

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


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

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

// 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("  ", " ");
//替换所有单个空格
for(int i=0;i

但是,与适当的正则表达式相比,这段代码非常难看而且速度很慢…

这种方法使用正则表达式,但希望在某种程度上仍然具有相当的可读性。首先,在多个空格上拆分输入字符串

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
替换为”。

对于非正则表达式选项,可以使用:

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();

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

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();
}
工作原理:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")
我们将在字符串中线性地检查每个可能的三字符子序列(在一种三字符滑动窗口中)。这三个字符将依次由变量
lhs
mid
rhs
表示

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

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

这里的微妙之处在于,我通过使用非空格字符初始化
lhs
mid
变量,避免了序列开头的特殊大小写。这些值是什么并不重要,只要它们不是空格,但我将它们设置为
\0
,以表明它们是特殊值。

经过仔细考虑,这里有一行:

这样做的结果是“abcdefghi xyz”

原始答案:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")
两行代码正则表达式解决方案:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")
tmp
“abcdefghi xyz”
然后:

结果
“abcdefghi xyz”


说明:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")
第一行代码删除单个空格,并为多个空格删除一个空格(因此
tmp
中字母i和x之间有3个空格)

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

第一行的深入解释:

var tmp = Regex.Replace("abc def ghi    xyz", "( )([^ ])", "$2")
我们将输入字符串与正则表达式匹配,正则表达式匹配一个空格和它旁边的非空格。我们还将这两个字符分为不同的组(我们使用
进行匿名分组)。 因此,对于
“abc def ghi xyz”
字符串,我们有以下匹配项和组:

匹配:
“d”
group1:
“”
group2:
“d”

匹配:
“g”
group1:
“”
group2:
“g”

匹配:
“x”
group1:
“”
group2:
“x”


我们正在使用for
Regex。Replace
方法将匹配替换为第二组的内容(非空白字符)

使用Regex将是您最好的选择。看起来这里已经回答了这个问题:多个空格似乎没有正确显示。第一个字符串示例在“ghi”和“xyz”之间有几个空格,而不是实际的文本(多个空格)。@Michael B:这个问题不是一回事。这很聪明。我有一部分人非常欣赏这个解决方案,但另一个不想让它靠近我的代码库。@aaron其实没那么复杂。我已经重命名了循环变量,以便更清楚地了解发生了什么。默认的string.split()实际上会删除所有的空格,所以我认为这不管用。@aaron,它只会删除一个空格,不会删除多个空格。我已经测试了这个代码,然后才把它放在答案中。你说得对。我也尝试过类似的方法,但有一两个逻辑错误使我无法得到正确的结果。