ChatGPT解决这个技术问题 Extra ChatGPT

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

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

例子:

1 2 3  4    5

将会:

1 2 3 4 5
状态机可以很容易地做到这一点,但如果你只需要它来删除空格,它可能有点过头了
我在重复的问题 stackoverflow.com/a/37592018/582061 中添加了关于不同方法的基准。正则表达式并不是最快的方法。
除非这是人们将“空白”缩写为“空格”的区域性问题,否则我不明白为什么有这么多答案试图替换多个连续 space 以外的任何内容(即 ' ''\u0020'、{ 4}、(char) 32) 个字符。

M
Matt

我喜欢使用:

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

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


稍作修改:Regex.Replace(source, @"(\s)\s+", "$1");这将返回找到的第一个空格类型。因此,如果您有 5 个选项卡,它将返回一个选项卡。万一有人喜欢这个。
@radistao 您的链接用于 Javascript 字符串替换,而不用于 C#。
@Shiva,/\s\s+/ 是标准的 POSIX 正则表达式语句,可以使用自己的语法转换/使用任何语言
本着@FBtenKate 解决方案的精神: Regex.Replace(source, @"(\s)\1+", "$1");将用一个替换多个相同的连续字符。
为了删除前导和尾随空格,您应该使用 Trim() 函数,例如 var myString = Regex.Replace(myString, @"\s+", " ").Trim();
c
chindirala sampath kumar
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");

我已经复制并粘贴了它,它可以工作。我真的不喜欢正则表达式,但这次它救了我的命。
@Craig 一个评论就足够了,IMO。 // 这个块用一个替换多个空格... :)
真的,RegEx 对此有点过分了。
@Joel:不能同意。实际上,我确信这种方式对于足够大的字符串比您的方式更有效,并且可以在一行中完成。哪来的矫枉过正?
@Oscar Joel 的代码不是遍历所有字符的简单循环!这是一个隐藏的嵌套循环,具有二次最坏情况。相比之下,这个正则表达式是线性的,只构建一个字符串(= 与 Joel 的代码相比,分配成本大大降低),而且引擎可以优化它(老实说,我怀疑 .NET 正则表达式是足够聪明,但理论上这个正则表达式可以很便宜地实现,它甚至不再有趣;它只需要一个具有三个状态的 DFA,每个状态一个转换,并且没有额外的信息)。
t
tvanfosson
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));

这比正则表达式更具可读性,我更喜欢它,因为我不需要学习其他语法
我喜欢它,因为它不需要正则表达式
这对于大字符串来说效率很低。
这也删除了前导和尾随空格。
我也更喜欢这个答案。我的老导师曾经说过“任何时候你有一个问题,你认为你需要正则表达式来解决,嗯……现在你有两个问题”
B
Brenda Bell

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

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

RegexOptions.Multiline 改变了 ^ 和 $ 的含义,因此它们匹配每行的开头和结尾 ($ = \n),而不是整个多行字符串。因为 \s 等效于 [ \f\n\r\t\v] ,所以即使 Multiline 选项关闭,也应该替换换行符。
马特的回答已经涵盖了这一点。我“相信”有 30 个人只是蒙上眼睛对这个答案投了赞成票:)
c
cuongle

另一种使用 LINQ 的方法:

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

喜欢这个解决方案!这个 2022 年是否有不利之处,或者为什么它不受欢迎。
F
Fahim Parkar

它比所有这些都简单得多:

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

如果字符串包含 3 个或更多空格的序列,这将远低于正则表达式“{2,}”的效率。
@JanGoyvaerts:即使有 10 个空格,当我进行快速而肮脏的测试时,正则表达式也会变慢。话虽如此,只需要一个充满空格的巨大子字符串就可以完全破坏 while 循环的性能。为了公平起见,我使用了我使用的 RegexOptions.Compiled,而不是较慢的 Regex.Replace。
RegexOptions.Compiled 增加了将正则表达式编译到 IL 中的大量开销。不要使用它,除非您的应用程序会经常使用正则表达式或在足够大的字符串上使用增加的匹配速度来抵消降低的编译速度。
这是一个极端低效的代码示例。哈哈。
@pcbabu 在许多情况下,它并不像看起来那么糟糕。 Replace() 方法将处理给定字符串中所有出现的两个空格,因此我们不会为字符串中的每个配对空格实例循环(并重新分配整个字符串)。一个新的分配将处理所有这些。我们只在有 3 个或更多空格一起时才重新运行循环,这对于许多输入源来说可能很少发生。如果你能证明它对你的数据来说是一个问题,那么就去编写状态机,将一个字符一个字符地推送到一个新的字符串构建器中。
S
ScubaSteve

即使是简单的任务,正则表达式也会相当慢。这将创建一个可在任何 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."

我喜欢扩展方法的想法,尽管可以优化例程。
J
Jan Goyvaerts
myString = Regex.Replace(myString, " {2,}", " ");

N
Nolonar

对于那些不喜欢 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 倍。与非编译或非静态正则表达式相比,这应该更快。

请记住,它不会删除前导或尾随空格,只会删除多次出现的空格。


如果要检查字符是否为空格,而不仅仅是空格 see my answer below
A
Aleks Andreev

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

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

如果你对正则表达式不太熟悉,这里有一个简短的解释:

{2,} 使正则表达式搜索其前面的字符,并查找 2 次到无限次之间的子字符串。
.Replace(temp, " ") 用空格替换字符串 temp 中的所有匹配项。

如果您想多次使用它,这里是一个更好的选择,因为它会在编译时创建正则表达式 IL:

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

r
ravish.hacker

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

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

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


您必须确保您的字符串中没有“()”或“)(”。否则 "wel()come to london)(" 变为 "wel come to london"。您可以尝试使用大量括号。所以使用 ((((())))) 而不是 ())))))((((( 而不是 )(。它仍然可以工作。不过,如果字符串包含 ((((())))))))))(((((,这将失败。
S
Stephen du Buis

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

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

结果:“0 1 2 3 4 5”


提醒一句:split 的使用虽然确实很容易理解,但会对性能产生惊人的负面影响。由于可以创建许多字符串,因此您必须注意内存使用情况,以防使用此方法处理大字符串。
J
Jamshaid K.
// 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";

J
Jay Bazuzi

根据乔尔的说法,安慰其他答案,并希望随着我的进展略有改善:

您可以使用 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 (" ");

J
Jay Bazuzi

我刚刚写了一个我喜欢的新 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 (" ");

为什么要创建扩展方法?为什么不直接使用 string.Join()?
T
The_Black_Smurf

许多答案都提供了正确的输出,但对于那些寻求最佳性能的人,我确实将 Nolanar's answer(这是性能的最佳答案)提高了大约 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();
    }

}

M
M.Hassan

使用正则表达式模式

    [ ]+    #only space

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

P
Paul Easter

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

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

由于我们处理的是空白空间,因此有点难以阅读,所以这里再次将“空格”替换为“_”。

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

“(?m:” 构造启用了“多行”选项。我通常喜欢在模式本身中包含我可以使用的任何选项,以便它更加独立。


L
Learner1947

我可以用这个删除空格

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 个空格
该 While 循环将处理所有要删除的双空格。
在循环中,您将替换空格字符,但随后使用 Trim() 您将删除所有删除前导和尾随 whitespace 字符,而不仅仅是空格。在用 Trim(' ') 修复它之后,问题就出现了,该问题从未要求删除前导和尾随(空白)空格。在通过完全删除 Trim(' ') 修复那个之后...您现在复制了 this old answer。另外,为什么要发布几乎是 C# 的代码,而这些代码只需稍作调整即可生效?
T
Tom Gullen

不使用正则表达式:

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

可以在短字符串上使用,但在有很多空格的长字符串上表现不佳。


A
Ahmed Aljaff

试试这个方法

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

这将删除尾随空格
抱歉这个错误,我修复了代码,现在它按预期工作 测试字符串:“1 2 3 4 9” 结果字符串:“1 2 3 4 9”
R
Reap

这是对 Nolonar original answer轻微修改

检查字符是否不仅仅是一个空格,而是任何空格,使用这个:

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

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

谢谢,这帮助了我。小错误:strValue 应该是 input。此外,IsWhiteSpace 包括换行符。您可能不想合并多个换行符,只要它会根据您的环境(\r\n\n)表现不同。在这种情况下,检查“CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.SpaceSeparator”。
@OliverSchimmer 是的,感谢您的更正。添加的 unicode 字符信息是一个很好的补充。随时进行编辑! :)
这不是对这个答案的重写吗? stackoverflow.com/a/33817748/56621
@AlexfromJitbit,它实际上是对 my answer 的修改,它比其他答案早了大约 2.5 年。
@Nolonar 是的,我承认在我的回答中,希望没问题
D
Demetris Leptos

去无赖怎么办?

public static string MinimizeWhiteSpace(
    this string _this)
    {
        if (_this != null)
        {
            var returned = new StringBuilder();
            var inWhiteSpace = false;
            var length = _this.Length;
            for (int i = 0; i < length; i++)
            {
                var character = _this[i];
                if (char.IsWhiteSpace(character))
                {
                    if (!inWhiteSpace)
                    {
                        inWhiteSpace = true;
                        returned.Append(' ');
                    }
                }
                else
                {
                    inWhiteSpace = false;
                    returned.Append(character);
                }
            }
            return returned.ToString();
        }
        else
        {
            return null;
        }
    }

P
Patrick Artner

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

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

public static class StringExtension
{
    public static string CondenseSpaces(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()
    {
        const string input = "     (five leading spaces)     (five internal spaces)     (five trailing spaces)     ";
        
        Console.WriteLine(" Input: \"{0}\"", input);
        Console.WriteLine("Output: \"{0}\"", StringExtension.CondenseSpaces(input));
    }
}

执行此程序会产生以下输出:

 Input: "     (five leading spaces)     (five internal spaces)     (five trailing spaces)     "
Output: " (five leading spaces) (five internal spaces) (five trailing spaces) "

乍一看,这是 Aggregate() 的一个很好、简短而直接的用法;但是,其中有一个错误。测试 acc.Length > 0 显然可以防止后面的 acc[acc.Length-1] != ' ' 条件出现 IndexOutOfRange 异常,但这会防止发出 前导 空格字符,因为此时 acc 为空。我有 corrected thisacc.Length == 0 || acc[acc.Length - 1] != ' ' 并且还扩展了示例代码以证明整个 s 中的单个和多个连续空格都得到了正确处理。
您可能会进行的一项优化是使用 new StringBuilder(s.Length) 初始化 acc,因为最长的结果 string 将是 - 当不进行替换时,因为 s 不包含连续空格字符 - 与输入的长度相同string。另外,我建议使用像 CollapseSpaces()CondenseSpaces() 这样的方法名称来更准确地描述它在做什么; “strip”听起来像是在删除 all 空格。
@LanceU.Matthews 感谢您的阅读和修复,您是对的。固定名称。
o
onedaywhen

老派:

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

G
Giedrius

我查看了建议的解决方案,找不到可以处理我的情况可接受的空白字符混合的解决方案,例如:

Regex.Replace(input, @"\s+", " ") - 如果它们与空格混合,它将吃掉你的换行符,例如 \n \n 序列将被替换为

Regex.Replace(source, @"(\s)\s+", "$1") - 它取决于空格的第一个字符,这意味着它可能再次吃掉你的换行符

Regex.Replace(source, @"[ ]{2,}", " ") - 当混合了空白字符时,它将无法正常工作 - 例如 "\t \t "

可能并不完美,但对我来说快速的解决方案是:

Regex.Replace(input, @"\s+", 
(match) => match.Value.IndexOf('\n') > -1 ? "\n" : " ", RegexOptions.Multiline)

想法是 - 换行符胜过空格和制表符。

这将无法正确处理 windows 换行符,但也很容易调整以使用它,不太了解正则表达式 - 可能适合单一模式。


我认为这是对另一个问题的答案。在这个问题中只提到了空格——不是制表符或换行符或“空白字符的混合”——所以虽然这可能是一个很好的分析,但我看不出这些信息与这里的相关性。
Downvotes 表示“无用”的内容(无论选民选择如何定义)并相对于其他答案将其推低;我练习了我的答案,因为在我看来,这个答案并没有提供与所问问题相关或有用的信息,因此,当试图找到一个专注于提出了问题。正如我所指出的,我认为这本身并不是一个糟糕的答案,我只是不认为它属于这里;如果 SO 上的某处没有至少一个 C# merge-adjacent-whitespace Q,我会感到惊讶。
B
Bibin Gangadharan

以下代码将所有多个空格删除为单个空格

    public string RemoveMultipleSpacesToSingle(string str)
    {
        string text = str;
        do
        {
            //text = text.Replace("  ", " ");
            text = Regex.Replace(text, @"\s+", " ");
        } while (text.Contains("  "));
        return text;
    }

为什么需要循环?您不相信 Regex.Replace() 第一次工作吗?此外,由于仅当字符连续 两次或多次 出现时才真正执行替换,因此您应该匹配:\s{2,}。但是,最重要的是,这并没有按照方法名称的建议或这个问题的要求进行:\s 不仅匹配空格,还匹配 任何空格 字符。
V
Vasilis Plavos

您可以使用 RemoveDoubleSpaces() 之类的方法创建 StringsExtensions 文件。

StringsExtensions.cs

public static string RemoveDoubleSpaces(this string value)  
{
  Regex regex = new Regex("[ ]{2,}", RegexOptions.None);
  value = regex.Replace(value, " ");

  // this removes space at the end of the value (like "demo ")
  // and space at the start of the value (like " hi")
  value = value.Trim(' ');

  return value;
}

然后你可以像这样使用它:

string stringInput =" hi here     is  a demo ";

string stringCleaned = stringInput.RemoveDoubleSpaces();

这是非常低效的。如果输入包含 8 个连续空格,则第一个循环将运行 3 次。第一个中的 StartsWith 必须搜索整个字符串以获取 false,如果字符串很大,则可能需要一些时间。第二和第三个循环是不必要的,第一个循环意味着最多可以有一个初始空间和最多一个最终空间。
让好的代码未经优化以保持清晰是一回事——而且根本不是一件坏事。但是,即使乍一看,这只是不必要的低效代码。在内部,Contains()Replace() 都必须使用 IndexOf()(或类似的东西)来定位指定的 string,所以您所说的是“扫描指定的字符串以查看是否需要替换它,而这又需要再次进行扫描。”这类似于 if (dict.ContainsKey(key)) value = dict[key]; 而不是 found = dict.TryGetValue(key, out value);。如果一刀切(续)
(续)解决方案使代码难以阅读或理解,那么应该使用 comments 而不是 BCL-method-calls-as-self-documentation 来描述正在发生的事情。至于您对 *sWith() 调用所做的事情,可以将其替换为 value = value.TrimEnd(' ').TrimStart(' ');,或者简单地说,value = value.Trim(' ');,但无论如何,删除单独的前导或尾随空格与这个问题无关。如果不出意外,已经有几个答案使用了 string.Replace(),而这个答案正在添加 nothing new
最近对该答案的更改意味着它与许多其他答案非常相似,因此它现在没有为问题添加任何新内容。
不过,修剪前导/尾随空格不是问题的一部分,扩展方法是语法糖;如果需要,读者可以轻松地将它们合并到他们的代码中。忽略这些微不足道的更改,您现在复制了 the accepted answerthis answer 和另外两个使用等效模式 " {2,}"。我会回应@AdrianHHH 的评论,并说这个答案没有添加任何新的、有用的 信息,因此在一个已经包含太多信息的问题上显得杂乱无章。