371

C#では、文字列内の複数のスペースを1つのスペースに置き換える方法はありますか。

例:

1 2 3  4    5

だろう:

1 2 3 4 5


  • ステートマシンでも簡単にできますが、スペースを削除するだけの場合は、やり過ぎる可能性があります。 - Adrian
  • 重複した質問でこれを実行するさまざまな方法についてベンチマークを追加しましたstackoverflow.com/a/37592018/582061。正規表現はこれを行うための最速の方法ではありませんでした。 - Stian Standahl

22 답변


390

RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
tempo = regex.Replace(tempo, " ");


  • コメントを投稿するだけで十分です、IMO。 //このブロックは複数の空白を1つの空白に置き換えます... :) - paulwhit
  • 本当に、RegExはこれにはやり過ぎです。 - Joel Coehoorn
  • しかし今、あなたは2つの問題を抱えています.... - seanb
  • @ジョエル:同意できません。十分に大きい文字列の場合、この方法があなたの方法よりも効率的であり、1行で実行できることを私は実際に確信しています。やり過ぎはどこにありますか。 - Konrad Rudolph
  • @Oscar Joelのコードは、すべての文字を単純にループするのではありません。それは二次の最悪のケースを持つ隠された入れ子のループです。これとは対照的に、この正規表現は線形で、1つの文字列のみを構築し(= Joelのコードに比べて割り当てコストが大幅に削減されます)、さらにエンジンはそれから最適化できます(正直なところ、.NET正規表現は疑いありません)。これに対しては十分スマートですが、理論的にはこの正規表現はそれほど面白くないほど安く実装することができます;それは3つの状態を持つDFA、それぞれ1つの遷移、そして追加情報を必要としません)。 - Konrad Rudolph

538

私は使うのが好きです:

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

なぜなら、それはあらゆる種類の空白(例えばタブ、改行など)の実行を捉え、それらを単一の空白に置き換えるからです。


  • わずかな修正:Regex.Replace(source、@ "(\ s)\ s +"、 "$ 1");これは最初に見つかった空白タイプを返します。したがって、5つのタブがある場合は、タブが返されます。誰かがこれを好む場合。 - F.B. ten Kate
  • @radistaoあなたのリンクはC#ではなくJavascript文字列置換用です。 - Shiva
  • @Shiva、/ \ s \ s + /は標準のPOSIX正規表現であり、独自の構文を使用して任意の言語で変換/使用できます。 - radistao
  • 良いオプションです。さらなる例は、あなたがtab-space-space-tab-newlineを持っているならば、それはタブを返すでしょう。 - goodeye
  • @ F.B.tenKateのソリューションの精神に沿って:Regex.Replace(source、@ "(\ s)\ 1 +"、 "$ 1");複数を置き換えます同一の1文字ずつ連続した文字。 - François Beaune

38

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


  • 正規表現も動作します。 - tvanfosson
  • これは正規表現より読みやすく、他の構文を習得する必要がないのでもっと好きです。 - Michael Bahig
  • Regexが必要ないので気に入っています - AleX_
  • これは大きな文字列に対しては非効率的です。 - DarcyThomas
  • これにより、前後のスペースも削除されます。 - Matzi

37

私はマットの答えが最善だと思いますが、それがまったく正しいとは思わない。改行を置き換えたい場合は、次のものを使用する必要があります。

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


  • RegexOptions.Multilineは^と$の意味を変更して、複数行の文字列全体ではなく、すべての行の始めと終わり($ = \ n)と一致するようにします。 \ sは[\ f \ n \ r \ t \ v]と同じなので、複数行オプションがオフの場合でも改行は置き換えられるべきです。 - SushiGuy
  • マットの答えは既にこれをカバーしています。私は信じています' 30人がこの回答を目隠しで投票しました:) - 123iamking

21

LINQを使うもう一つのアプローチ:

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


21

それよりもずっと簡単です。

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


  • これは正規表現よりはるかに効率が悪いでしょう。 {2、}"文字列に3つ以上のスペースのシーケンスが含まれる場合 - Jan Goyvaerts
  • @ JanGoyvaerts:10個のスペースがあっても、正規表現は私が素早く汚いテストをしたときは遅くなりました。そうは言っても、whileループのパフォーマンスを完全に無効にするには、スペースでいっぱいの巨大なサブストリング1つだけが必要です。公平を期すために、私は遅いRegex.Replaceではなく、RegexOptions.Compiledを使用しました。 - Brian
  • RegexOptions.Compiledは、正規表現をILにコンパイルするための多くのオーバーヘッドを追加します。アプリケーションが正規表現を十分に頻繁に使用する場合、または十分に大きい文字列に対して使用する場合を除き、使用しないでください。マッチング速度が速くなるとコンパイル速度が遅くなります。 - Jan Goyvaerts

14

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


19

単純なタスクでも正規表現はかなり遅くなる可能性があります。これはどのメソッドからでも使用できる拡張メソッドを作成します。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."


8

好きではない人のために、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倍高速でした。コンパイルされていない、あるいは静的でない正規表現と比べて、これはもっと速いはずです。

覚えておいて、それがすることではない先頭または末尾のスペースは削除してください。


  • これはパフォーマンスに対する最良の答えです。 - The_Black_Smurf

8

あなたは単に一行の解決策でこれを行うことができます!

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

お望みなら、他の括弧(あるいは他の文字)を選ぶことができます。


  • 文字列に"()"がないことを確認する必要があります。またはその中の「)」(または"wel()come to london)("になる"wel come to london"。あなたはたくさんの括弧を使ってみることができます。だから使う((((()))))の代わりに()そして)))))(((((の代わりに)(。それはまだ動作します。それでも、文字列に((((()))))または)))))(((((、これは失敗します。 - nmit026

5

これはより短いバージョンです。これは、これを1回しか実行しない場合にのみ使用する必要があります。Regex呼び出されるたびにクラス。

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

あなたがあまりにも正規表現に精通していない場合は、ここで簡単な説明があります:

{2,}正規表現にその前の文字を検索させ、2から無制限の間の部分文字列を見つけます。

.Replace(temp, " ")文字列temp内のすべての一致をスペースで置き換えます。

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

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


5

正規表現なし、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"


  • 注意点:splitを使用すると、理解するのは非常に簡単ですが、パフォーマンスに驚くほど悪い影響を与える可能性があります。多くの文字列を作成できるので、この方法で大きな文字列を処理する場合に備えて、メモリ使用量を監視する必要があります。 - Pac0

4

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


2

私はちょうど新しい書きました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 (" ");


  • なぜ拡張メソッドを作成するのですか?なぜ単にstring.Join()を使わないのですか? - Eric Schoonover

2

私はこれがかなり古いことを知っています、しかしほとんど同じことを達成しようとしている間、これに遭遇しました。 RegEx Buddyでこの解決策を見つけました。このパターンは、すべてのダブルスペースをシングルスペースに置き換え、また前後のスペースを削除します。

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

私たちが空のスペースを扱っているので、それは読むのが少し難しいので、ここでまたここでは "スペース"が "_"に置き換えられています。

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

"(?m:"構文は "複数行"オプションを有効にします。私は一般的にパターン自体の中にできるオプションをすべて含めることを好みます。


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
  • Whileループは、削除されるすべてのダブルスペースを処理します。 - Learner1947

1

多くの答えが正しい出力を提供していますが、最高のパフォーマンスを探している人のために、私は改善しました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

この方法を試してください

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

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


  • テキストにまだ含まれていないと仮定します(char)22 - onedaywhen

0

正規表現を使わないで

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

短い文字列では使用できますが、スペースの多い長い文字列ではパフォーマンスが低下します。


0

正規表現パターンを使う

    [ ]+    #only space

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


0

のミックスStringBuilderそしてEnumerable.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 "

リンクされた質問


関連する質問

最近の質問