C#で複数のスペースを1つのスペースに置き換えるにはどうすればよいですか?


439

文字列内の複数のスペースをC#の1つのスペースのみに置き換えるにはどうすればよいですか?

例:

1 2 3  4    5

だろう:

1 2 3 4 5

1
状態マシンはそれを簡単に行うことができますが、スペースを削除するためだけに必要な場合はおそらくやり過ぎです
Adrian

重複する質問でこれを行うためのさまざまな方法のベンチマークを追加しましたstackoverflow.com/a/37592018/582061。正規表現はこれを行う最速の方法ではありませんでした。
Stian Standahl

回答:


468
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 2008年

9
IMO、@ Craigのコメントで十分です。//このブロックは複数のスペースを1つに置き換えます... :)
08

6
本当に、RegExはこれに対して過剰です。
Joel Coehoorn、2008年

11
@ジョエル:同意できません。この方法は、十分に大きい文字列の場合、あなたの方法よりも効率的で、1行で実行できると確信しています。やり過ぎはどこですか
Konrad Rudolph

24
@オスカー・ジョエルのコードは、すべてのキャラクターをループするだけではありません!これは、2次ワーストケースを持つ非表示のネストされたループです。対照的に、この正規表現は線形であり、単一の文字列(= Joelのコードと比較して大幅に削減された割り当てコスト)を構築し、さらにエンジンはそれを完全に最適化できます(正直に言うと、.NET正規表現がこれには十分スマートですが、理論的にはこの正規表現は非常に安価に実装できるため、面白くさえありません。必要なのは、3つの状態、それぞれ1つの遷移、追加情報のないDFAだけです。
Konrad Rudolph

623

私は使いたい:

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

これは、あらゆる種類の空白(タブ、改行など)の実行をキャッチし、それらを単一のスペースに置き換えるためです。


43
わずかな変更:Regex.Replace(source、@ "(\ s)\ s +"、 "$ 1"); これにより、最初に見つかった空白タイプが返されます。したがって、5つのタブがある場合、タブが返されます。誰かがこれを好む場合。
FB

@radistaoリンクはJavaScript文字列置換用であり、C#用ではありません。
Shiva 14

1
@Shiva、/ \ s \ s + /は標準のPOSIX正規表現ステートメントであり、独自の構文を使用して任意の言語で変換/使用できます
radistao

4
@FBtenKateのソリューションの精神:Regex.Replace(source、@ "(\ s)\ 1+"、 "$ 1"); 複数の同一の連続した文字を1つの文字に置き換えます。
フランソワ・ボーヌ

1
先頭と末尾の空白を削除するには、var myString = Regex.Replace(myString、@ "\ s +"、 "").Trim();のように、これと共にTrim()関数を使用する必要があります。
Harish Nayak

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

6
これは正規表現よりも読みやすくなっています。他の構文を学ぶ必要がないので、私はもっと好きです
Michael Bahig

9
Regexを必要としないため、気に入っています
AleX_

3
これは、大きな文字列の場合は非効率的です。
DarcyThomas

3
これにより、先頭と末尾のスペースも削除されます。
Matzi 2017

1
私もこの答えを好みます。私の古いメンターは、「あなたが正規表現を解決する必要があると思う問題があるときはいつでも...今、あなたは2つの問題を抱えています」と言っていました<wink>
ウィリアム・マドンナ・ジュニア

38

マットの答えが一番だと思いますが、それが正しいとは思いません。改行を置き換える場合は、以下を使用する必要があります。

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

4
RegexOptions.Multilineは、^と$の意味を変更して、複数行の文字列全体ではなく、すべての行の先頭と末尾($ = \ n)に一致させます。\ sは[\ f \ n \ r \ t \ v]と同等であるため、複数行オプションがオフの場合でも改行を置き換える必要があります。
SushiGuy

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、2008年

2
@JanGoyvaerts:スペースが10個ある場合でも、すばやくダーティーなテストをすると、正規表現が遅くなりました。そうは言っても、whileループのパフォーマンスを完全に無効にするために必要なのは、スペースでいっぱいの1つの巨大な部分文字列だけです。公平を期すために、遅いRegex.Replaceではなく、RegexOptions.Compiledを使用しました。
ブライアン

5
RegexOptions.Compiledは、正規表現をILにコンパイルするための多くのオーバーヘッドを追加します。アプリケーションが正規表現を十分に頻繁に使用するか、一致速度の増加がコンパイル速度の低下を相殺するほど十分に大きい文字列で使用する場合を除いて、これを使用しないでください。
Jan Goyvaerts、2013

これは非常に非効率的なコードの例です。笑。
pcbabu

1
@pcbabuそれは多くの場合に思われるほど悪くはありません。このReplace()メソッドは、指定された文字列内の2つのスペースのすべての出現を処理するため、文字列内のペアになっているスペースのインスタンスごとにループ(および文字列全体を再割り当て)しません。1つの新しい割り当てでそれらすべてを処理します。3つ以上のスペースが一緒にある場合にのみループを再実行します。これは、多くの入力ソースでまれに発生する可能性があります。データに問題があることを示すことができる場合は、ステートマシンを作成して、新しい文字列ビルダーに1文字ずつプッシュします。
Joel Coehoorn

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倍高速でした。コンパイルされていない、または静的でない正規表現と比較すると、これはさらに高速です。

先頭または末尾のスペース削除され、そのような複数のオカレンスのみが削除されることに注意してください。


文字が空白だけでなく空白であるかどうかを確認したい場合 は、以下の私の答えを参照してください
シェムリアップ

8

これは、1行のソリューションで簡単に実行できます。

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

これを複数回使用する場合は、コンパイル時に正規表現ILを作成するため、より良いオプションがここにあります。

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

7

正規表現なし、Linqなし...前後のスペースを削除し、埋め込まれた複数のスペースセグメントを1つのスペースに減らします。

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

結果: "0 1 2 3 4 5"


1
注意:分割を使用すると、実際には非常に簡単に理解できますが、驚くほどパフォーマンスに悪影響を与える可能性があります。多くの文字列が作成される可能性があるため、このメソッドで大きな文字列を処理する場合は、メモリ使用量を監視する必要があります。
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());
}

これのすばらしい点の1つは、要素に対して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.

はい。ただし、2つの空白を1つに置き換えるだけです。これはX個のスペースに役立ちません
MGot90 '26 / 07/26

1
そのWhileループは、削除されるすべての二重スペースを処理します。
Learner1947 2017年

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 2018

間違いを犯して申し訳ありませんが、コードを修正しました。期待どおりに動作します。テストされた文字列: "1 2 3 4 9"結果文字列: "1 2 3 4 9"
Ahmed Aljaff

1

これはNolonarの元の回答を少し変更したものです。

文字が単なるスペースではなく空白であるかどうかを確認するには、次のようにします。

複数の空白文字を1つのスペースに置き換えます。

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

古いskool:

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 "
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.