如何在C#中用单个空格替换多个空格?


438

如何用C#中的一个空格替换字符串中的多个空格?

例:

1 2 3  4    5

将会:

1 2 3 4 5

1
一台状态机可以轻松地做到这一点,但是如果您只需要删除空间就可以用它来矫
Adrian 2012年

我在重复的问题stackoverflow.com/a/37592018/582061中添加了执行此操作的不同方法的基准。正则表达式不是最快的方法。
斯蒂安·斯坦达希尔

Answers:


467
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");

2
我已经复制并粘贴了它,并且可以正常工作。我真的不喜欢REgex,但这一次可以挽救我的生命。
Pokus

9
IMO,@ Craig发表评论就足够了。//此块用一个空格替换了多个空格... :)
paulwhit

6
确实,RegEx在这方面过于矫kill过正。
Joel Coehoorn

11
@乔尔:不同意。实际上,我可以肯定,对于足够大的字符串,这种方法比您的方法更有效,并且可以在一行中完成。过度杀人在哪里?
康拉德·鲁道夫

24
@Oscar Joel的代码并不是遍历所有字符的简单循环!这是一个隐藏的嵌套循环,具有二次最坏的情况。相比之下,此正则表达式是线性的,仅建立一个字符串(与Joel的代码相比,=大大减少了分配成本),此外,引擎可以对其进行优化(说实话,我怀疑.NET regex是否是这样做足够聪明,但是从理论上讲,这种正则表达式可以以非常便宜的方式实现,以至于不再有趣;它只需要一个DFA,它具有三个状态,每个状态一个转换,并且没有其他信息)。
康拉德·鲁道夫

622

我喜欢使用:

myString = Regex.Replace(myString, @"\s+", " ");

因为它将捕获任何类型的空格(例如,制表符,换行符等),并将其替换为单个空格。


42
轻微修改:Regex.Replace(source,@“(\ s)\ s +”,“ $ 1”); 这将返回找到的第一个空白类型。因此,如果您有5个标签,它将返回一个标签。如果有人喜欢这个。
FB十凯特

@radistao您的链接用于替换Javascript字符串,而不用于C#。
湿婆

1
@Shiva,/ \ s \ s + /是标准的POSIX正则表达式语句,可以使用自己的语法以任何语言进行转换/使用
radistao 2014年

4
本着@FBtenKate解决方案的精神:Regex.Replace(source,@“(\ s)\ 1+”,“ $ 1”); 会将多个相同的连续字符替换为一个字符。
弗朗索瓦·博恩

1
为了删除开头和结尾的空格,您应该对此使用Trim()函数,例如var myString = Regex.Replace(myString,@“ \ s +”,“”).Trim();
Harish Nayak

50
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));

6
这比regex更具可读性,我更喜欢它,因为我不需要学习其他语法
Michael Bahig

9
我喜欢它,因为它不需要Regex
AleX_

3
这对于大字符串将是低效的。
DarcyThomas

3
这也将删除前导和尾随空格。
Matzi'2

1
我也更喜欢这个答案。我的老导师曾经说过:“每当您遇到问题时,您都认为需要Regex解决,好吧……现在您遇到了两个问题”。<眨眼>
威廉·麦当娜

38

我认为Matt的答案是最好的,但我不认为这是正确的。如果要替换换行符,则必须使用:

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);

4
RegexOptions.Multiline更改^和$的含义,因此它们匹配每行的开头和结尾($ = \ n),而不是整个多行字符串。因为\ s等效于[\ f \ n \ r \ t \ v],即使关闭了“多行”选项,也应替换换行符。
SushiGuy 2012年

1
马特的答案已经涵盖了这一点。我“相信” 30个人,只是蒙住了眼睛投票赞成这个答案:)
123iamking

26

使用LINQ的另一种方法:

 var list = str.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));
 str = string.Join(" ", list);

23

比这简单得多:

while(str.Contains("  ")) str = str.Replace("  ", " ");

23
如果字符串包含3个或更多空格的序列,这将比正则表达式“ {2,}”的效率低得多。
Jan Goyvaerts

2
@JanGoyvaerts:即使有10个空格,当我进行快速而肮脏的测试时,正则表达式也较慢。话虽如此,它只需要一个充满空格的巨型子串就可以完全杀死while循环的性能。为了公平起见,我使用了RegexOptions.Compiled,而不是较慢的Regex.Replace。
Brian

5
RegexOptions.Compiled增加了很多将正则表达式编译为IL的开销。除非您的应用程序经常使用正则表达式或在足够大的字符串上使用正则表达式,否则增加的匹配速度可以抵消降低的编译速度,请不要使用它。
Jan Goyvaerts

这是效率极低的示例。大声笑。
pcbabu

1
@pcbabu这并不像很多情况下看起来那么糟糕。该Replace()方法将处理给定字符串中两个空格的所有出现,因此我们不会为字符串中配对空格的每个实例循环(并重新分配整个字符串)。一种新的分配将处理所有这些分配。我们只有在3个或更多空格在一起时才重新运行循环,对于许多输入源来说,这种情况很少发生。如果可以显示出它成为数据问题,那么请编写状态机以将一个字符一个字符地推送到新的stringbuilder中。
Joel

21

即使执行简单的任务,正则表达式也可能相当慢。这将创建一个扩展方法,该扩展方法可以从任何方法中使用string

    public static class StringExtension
    {
        public static String ReduceWhitespace(this String value)
        {
            var newString = new StringBuilder();
            bool previousIsWhitespace = false;
            for (int i = 0; i < value.Length; i++)
            {
                if (Char.IsWhiteSpace(value[i]))
                {
                    if (previousIsWhitespace)
                    {
                        continue;
                    }

                    previousIsWhitespace = true;
                }
                else
                {
                    previousIsWhitespace = false;
                }

                newString.Append(value[i]);
            }

            return newString.ToString();
        }
    }

它可以这样使用:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."


11

对于那些不喜欢的人Regex,这里是一种使用的方法StringBuilder

    public static string FilterWhiteSpaces(string input)
    {
        if (input == null)
            return string.Empty;

        StringBuilder stringBuilder = new StringBuilder(input.Length);
        for (int i = 0; i < input.Length; i++)
        {
            char c = input[i];
            if (i == 0 || c != ' ' || (c == ' ' && input[i - 1] != ' '))
                stringBuilder.Append(c);
        }
        return stringBuilder.ToString();
    }

在我的测试中,与静态编译的Regex相比,使用大量中小型字符串时,此方法平均快16倍。与非编译或非静态Regex相比,这应该更快。

请记住,它并没有删除开头或结尾的空格,只有这样多次出现。


如果要检查字符是否为空格,而不仅仅是空格, 请参阅下面的答案
收获

8

您可以简单地在一站式解决方案中做到这一点!

string s = "welcome to  london";
s.Replace(" ", "()").Replace(")(", "").Replace("()", " ");

如果愿意,您可以选择其他方括号(甚至其他字符)。


1
您必须确保您的字符串中没有“()”或“)(”。否则"wel()come to london)("会变成"wel come to london"。您可以尝试使用许多方括号。因此请使用((((()))))代替())))))(((((代替)(。它仍然可以使用。字符串包含((((())))))))))(((((,则将失败
。– nmit026

7

这是一个较短的版本,仅在您仅执行一次时才应使用,因为它Regex每次调用时都会创建该类的新实例。

temp = new Regex(" {2,}").Replace(temp, " "); 

如果您不太熟悉正则表达式,请执行以下简短说明:

{2,}使得用于它前面的字符正则表达式搜索,发现2和无限次之间的子串。
.Replace(temp, " ")在字符串临时用空格替换所有的比赛。

如果要多次使用它,这是一个更好的选择,因为它会在编译时创建regex IL:

Regex singleSpacify = new Regex(" {2,}", RegexOptions.Compiled);
temp = singleSpacify.Replace(temp, " ");

7

没有正则表达式,没有Linq ...删除前导和尾随空格,以及将任何嵌入的多个空格分段减少到一个空格

string myString = "   0 1 2  3   4               5  ";
myString = string.Join(" ", myString.Split(new char[] { ' ' }, 
StringSplitOptions.RemoveEmptyEntries));

结果:“ 0 1 2 3 4 5”


1
提醒您:虽然使用split确实很容易理解,但却会对性能产生令人惊讶的负面影响。由于可以创建许多字符串,因此,如果使用此方法处理大字符串,则必须注意内存使用情况。
Pac0

5

根据Joel的建议,总结其他答案,并希望随着我的进行会有所改善:

您可以使用Regex.Replace()

string s = Regex.Replace (
    "   1  2    4 5", 
    @"[ ]{2,}", 
    " "
    );

或搭配String.Split()

static class StringExtensions
{
    public static string Join(this IList<string> value, string separator)
    {
        return string.Join(separator, value.ToArray());
    }
}

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");

3

我刚刚写了一个Join我喜欢的新书,所以我想用它来回答:

public static string Join<T>(this IEnumerable<T> source, string separator)
{
    return string.Join(separator, source.Select(e => e.ToString()).ToArray());
}

关于此的很酷的事情之一是,它通过在元素上调用ToString()来处理不是字符串的集合。用法仍然相同:

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");

2
为什么要创建扩展方法?为什么不只使用string.Join()?
Eric Sc​​hoonover,

3
      // Mysample string
            string str ="hi you           are          a demo";

            //Split the words based on white sapce
            var demo= str .Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));

            //Join the values back and add a single space in between
                    str = string.Join(" ", demo);

//output: string str ="hi you are a demo";

2

我知道这已经很老了,但是在尝试完成几乎同一件事时就碰到了这一点。在RegEx Buddy中找到了此解决方案。此模式将用单个空格替换所有双重空格,并修剪前导和尾随空格。

pattern: (?m:^ +| +$|( ){2,})
replacement: $1

由于我们正在处理空白空间,因此有点难以阅读,因此这里还是用“ _”代替了“空格”。

pattern: (?m:^_+|_+$|(_){2,})  <-- don't use this, just for illustration.

“(?m:”构造启用了“多行”选项。我通常喜欢在模式本身中包括我可以包含的所有选项,这样它就更加独立了。


2

许多答案提供了正确的输出,但是对于那些寻求最佳性能的人,我确实将Nolanar的答案(这是性能的最佳答案)提高了约10%。

public static string MergeSpaces(this string str)
{

    if (str == null)
    {
        return null;
    }
    else
    {
        StringBuilder stringBuilder = new StringBuilder(str.Length);

        int i = 0;
        foreach (char c in str)
        {
            if (c != ' ' || i == 0 || str[i - 1] != ' ')
                stringBuilder.Append(c);
            i++;
        }
        return stringBuilder.ToString();
    }

}

1

我可以用这个删除空格

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.

是的,但是您只能将两个空白替换为一个。这将无助于X的空格数
MGot90 '16

1
While循环将照顾所有要删除的双精度空格。
Learner1947年

1

使用正则表达式模式

    [ ]+    #only space

   var text = Regex.Replace(inputString, @"[ ]+", " ");

1

试试这个方法

private string removeNestedWhitespaces(char[] st)
{
    StringBuilder sb = new StringBuilder();
    int indx = 0, length = st.Length;
    while (indx < length)
    {
        sb.Append(st[indx]);
        indx++;
        while (indx < length && st[indx] == ' ')
            indx++;
        if(sb.Length > 1  && sb[0] != ' ')
            sb.Append(' ');
    }
    return sb.ToString();
}

像这样使用它:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());

这将删除尾随空格
The_Black_Smurf

对不起,我修复了代码,现在它可以按预期的方式工作,已测试的字符串:“ 1 2 3 4 9”结果字符串:“ 1 2 3 4 9”
Ahmed Aljaff

1

这是对Nolonar原始答案略微修改

检查字符是否不仅是空格,而且是任何空格,请使用以下命令:

它将用单个空格替换任何多个空格字符。

public static string FilterWhiteSpaces(string input)
{
    if (input == null)
        return string.Empty;

    var stringBuilder = new StringBuilder(input.Length);
    for (int i = 0; i < input.Length; i++)
    {
        char c = input[i];
        if (i == 0 || !char.IsWhiteSpace(c) || (char.IsWhiteSpace(c) && 
            !char.IsWhiteSpace(strValue[i - 1])))
            stringBuilder.Append(c);
    }
    return stringBuilder.ToString();
}

0

老派

string oldText = "   1 2  3   4    5     ";
string newText = oldText
                    .Replace("  ", " " + (char)22 )
                    .Replace( (char)22 + " ", "" )
                    .Replace( (char)22 + "", "" );

Assert.That( newText, Is.EqualTo( " 1 2 3 4 5 " ) );

0

不使用正则表达式:

while (myString.IndexOf("  ", StringComparison.CurrentCulture) != -1)
{
    myString = myString.Replace("  ", " ");
}

可以在短字符串上使用,但是在带有很多空格的长字符串上效果不佳。


0

StringBuilderEnumerable.Aggregate()的混合使用,作为字符串的扩展方法:

using System;
using System.Linq;
using System.Text;

public static class StringExtension
{
    public static string StripSpaces(this string s)
    {
        return s.Aggregate(new StringBuilder(), (acc, c) =>
        {
            if (c != ' ' || acc.Length > 0 && acc[acc.Length-1] != ' ')
                acc.Append(c);

            return acc;
        }).ToString();
    }

    public static void Main()
    {
        Console.WriteLine("\"" + StringExtension.StripSpaces("1   Hello       World  2   ") + "\"");
    }
}

输入:

"1   Hello       World  2   "

输出:

"1 Hello World 2 "
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.