複数の空白を1つの空白に置き換える方法


108

次のような文字列があるとします。

"Hello     how are   you           doing?"

複数のスペースを1つのスペースに変換する機能をお願いします。

だから私は得るでしょう:

"Hello how are you doing?"

私は正規表現を使用したり電話をかけたりできることを知っています

string s = "Hello     how are   you           doing?".replace("  "," ");

しかし、すべての連続する空白が1つだけに置き換えられることを確認するために、それを複数回呼び出す必要があります。

このための組み込みメソッドはすでにありますか?


明確にしてもらえますか:スペースだけを扱っているのですか、それとも「すべて」の空白を扱っているのですか?
ジョンスキート

そして、スペース以外の空白をスペースに変換しますか?
Jon Skeet、

連続するすべての空白は最大で1にする必要があることを意味しました
マット


考慮すべき2つのこと:1. char.IsWhiteSpaceキャリッジリターンを含む、改行などの2「空白」がおそらくより正確Char.GetUnicodeCategory(CH)= Globalization.UnicodeCategory.SpaceSeparatorでテストされている
smirkingman

回答:


196
string cleanedString = System.Text.RegularExpressions.Regex.Replace(dirtyString,@"\s+"," ");

40
imo、それらに
慣れるの

8
アプリケーションがタイムクリティカルでない場合は、1マイクロ秒の処理オーバーヘッドを許容できます。
ダニエル

16
「\ s」は空白だけでなく改行文字も置換することに注意してください。
Bart Kiers、2009

12
スペースが欲しいだけなら、パターンを "[] +"に切り替えてください
Tim Hoolihan

9
単一の空白を置き換えないようにするために、「+」の代わりに「{2、}」を使用しないでください。
angularsen

52

この質問は、他のポスターがそうであると思ったほど簡単ではありません(私が最初にそう思ったように)-質問は必要なほど正確ではないためです。

「スペース」と「ホワイトスペース」には違いがあります。スペースのみを意味する場合は、の正規表現を使用する必要があります" {2,}"。あなたが意味する場合は任意の空白を、それは別の問題です。すべての空白をスペースに変換する必要がありますか?最初と最後のスペースはどうなりますか?

以下のベンチマークでは、スペースのみに関心があり、最初と最後であっても、単一のスペースに対しては何もしたくないと想定しています。

ほとんどの場合、正確さはパフォーマンスよりも重要です。Split / Joinソリューションが先頭/末尾の空白(単一のスペースであっても)を削除するという事実は、指定された要件(もちろん不完全かもしれません)までは正しくありません。

ベンチマークはMiniBenchを使用しています

using System;
using System.Text.RegularExpressions;
using MiniBench;

internal class Program
{
    public static void Main(string[] args)
    {

        int size = int.Parse(args[0]);
        int gapBetweenExtraSpaces = int.Parse(args[1]);

        char[] chars = new char[size];
        for (int i=0; i < size/2; i += 2)
        {
            // Make sure there actually *is* something to do
            chars[i*2] = (i % gapBetweenExtraSpaces == 1) ? ' ' : 'x';
            chars[i*2 + 1] = ' ';
        }
        // Just to make sure we don't have a \0 at the end
        // for odd sizes
        chars[chars.Length-1] = 'y';

        string bigString = new string(chars);
        // Assume that one form works :)
        string normalized = NormalizeWithSplitAndJoin(bigString);


        var suite = new TestSuite<string, string>("Normalize")
            .Plus(NormalizeWithSplitAndJoin)
            .Plus(NormalizeWithRegex)
            .RunTests(bigString, normalized);

        suite.Display(ResultColumns.All, suite.FindBest());
    }

    private static readonly Regex MultipleSpaces = 
        new Regex(@" {2,}", RegexOptions.Compiled);

    static string NormalizeWithRegex(string input)
    {
        return MultipleSpaces.Replace(input, " ");
    }

    // Guessing as the post doesn't specify what to use
    private static readonly char[] Whitespace =
        new char[] { ' ' };

    static string NormalizeWithSplitAndJoin(string input)
    {
        string[] split = input.Split
            (Whitespace, StringSplitOptions.RemoveEmptyEntries);
        return string.Join(" ", split);
    }
}

いくつかのテスト実行:

c:\Users\Jon\Test>test 1000 50
============ Normalize ============
NormalizeWithSplitAndJoin  1159091 0:30.258 22.93
NormalizeWithRegex        26378882 0:30.025  1.00

c:\Users\Jon\Test>test 1000 5
============ Normalize ============
NormalizeWithSplitAndJoin  947540 0:30.013 1.07
NormalizeWithRegex        1003862 0:29.610 1.00


c:\Users\Jon\Test>test 1000 1001
============ Normalize ============
NormalizeWithSplitAndJoin  1156299 0:29.898 21.99
NormalizeWithRegex        23243802 0:27.335  1.00

ここで、最初の数値は反復回数、2番目は所要時間、3番目はスケーリングされたスコアで、1.0が最高です。

これは、少なくとも一部のケース(これを含む)で、正規表現分割/結合ソリューションよりも優れたパフォーマンスを発揮できることを示しています。

ただし、「すべて空白」の要件に変更すると、Split / Join 優先されます。多くの場合そうであるように、悪魔は細部に...


1
素晴らしい分析。ですから、私たちはどちらも程度の差はあっても正しいように見えます。私の回答のコードは、文字列内および最初と最後からすべての空白文字や制御文字を正規化する機能を持つ、より大きな関数から取得されました。
スコットドーマン

1
指定した空白文字だけで、ほとんどのテストでは、正規表現と分割/結合はほぼ同じでした。S/ Jには、正確さと複雑さを犠牲にして、非常に小さなメリットがあります。これらの理由から、通常は正規表現を使用します。誤解しないでください-私は正規表現のファンから遠く離れていますが、パフォーマンスを実際に最初にテストせずに、パフォーマンスのためにもっと複雑なコードを書くのは好きではありません。
Jon Skeet、

NormalizeWithSplitAndJoinは、さらに多くのガベージを作成します。実際の問題が、より多くのGC時間に到達するかどうかは、マークよりもわかりません。
Ian Ringrose

@IanRingroseどんなゴミが作れるの?
Dronz

18

通常のエクスプレスインが最も簡単な方法です。正規表現を正しい方法で記述すれば、複数回の呼び出しは必要ありません。

これを次のように変更します。

string s = System.Text.RegularExpressions.Regex.Replace(s, @"\s{2,}", " "); 

私の1つの問題@"\s{2,}"は、単一のタブやその他のUnicodeスペース文字をスペースに置き換えることができないことです。2つのタブをスペースに置き換える場合は、おそらく1つのタブをスペースに置き換える必要があります。@"\s+"あなたのためにそれを行います。
David Specht

17

既存の回答は問題ありませんが、機能しない 1つのアプローチを指摘したいと思います。

public static string DontUseThisToCollapseSpaces(string text)
{
    while (text.IndexOf("  ") != -1)
    {
        text = text.Replace("  ", " ");
    }
    return text;
}

これは永久にループする可能性があります。誰もが理由を推測するのを気にしますか?(私がこれに遭遇したのは、数年前にニュースグループの質問として尋ねられたときだけでした...誰かが実際に問題としてそれに遭遇しました。)


この質問がSOに戻ったときのことを覚えていると思います。IndexOfは、Replaceが無視しない特定の文字を無視します。したがって、二重スペースは常に存在し、削除されることはありませんでした。
ブランドン、

19
これは、IndexOfが一部のUnicode文字を無視するためです。この場合の特定の原因は、一部のアジア文字iircです。うーん、Googleによると、ゼロ幅の非結合子です。
ahawker '08 / 08/14

私が学んだこと、ハードな方法:( stackoverflow.com/questions/9260693/...
アントニオ・バクラ

私は難しい方法を学びました。特に、2つのゼロ幅非結合子(\ u200C \ u200C)があります。IndexOfはこの「ダブルスペース」のインデックスを返しますが、Replaceはそれを置き換えません。IndexOfでは、Replaceと同じように動作するようにStringComparsion(Ordinal)を指定する必要があるためだと思います。この方法では、これらの2つはどちらも「ダブルスペース」を見つけません。もっとStringComparsionについてdocs.microsoft.com/en-us/dotnet/api/...
マーティンBrabec

4

すでに指摘したように、これは正規表現で簡単に実行できます。先頭/末尾の空白を取り除くために.trim()を追加したい場合があることを追加します。


4

これが私が取り組むソリューションです。RegExおよびString.Splitなし。

public static string TrimWhiteSpace(this string Value)
{
    StringBuilder sbOut = new StringBuilder();
    if (!string.IsNullOrEmpty(Value))
    {
        bool IsWhiteSpace = false;
        for (int i = 0; i < Value.Length; i++)
        {
            if (char.IsWhiteSpace(Value[i])) //Comparion with WhiteSpace
            {
                if (!IsWhiteSpace) //Comparison with previous Char
                {
                    sbOut.Append(Value[i]);
                    IsWhiteSpace = true;
                }
            }
            else
            {
                IsWhiteSpace = false;
                sbOut.Append(Value[i]);
            }
        }
    }
    return sbOut.ToString();
}

だからあなたはできる:

string cleanedString = dirtyString.TrimWhiteSpace();

4

高速な余分な空白除去機能...これは最も高速なもので、Felipe Machadoのインプレースコピーに基づいています。

static string InPlaceCharArray(string str)
{
    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;
    bool lastWasWS = false;
    for (int i = 0; i < len; i++)
    {
        var ch = src[i];
        if (src[i] == '\u0020')
        {
            if (lastWasWS == false)
            {
                src[dstIdx++] = ch;
                lastWasWS = true;
            }
        }
        else
        { 
            lastWasWS = false;
            src[dstIdx++] = ch;
        }
    }
    return new string(src, 0, dstIdx);
}

ベンチマーク...

InPlaceCharArraySpaceOnlyがCodeProject 2015のFelipe Machadoによって作成され、マルチスペースの削除のためにSunsetquestによって変更されました。 時間:3.75ティック

InPlaceCharArray フェリペ・マチャド 2015とややマルチスペースを除去するためSunsetquestによって変更。 時間6.50ティック (タブもサポート)

Jon SkeetによるSplitAndJoinOnSpace 。 時間:13.25ティック

StringBuilderによるfubo 時間:13.5ティック(タブもサポート)

Jon Skeetによるコンパイル付きの正規表現。 時間:17ティック

StringBuilderによるDavid S 2013 時間:30.5ティック

ブランドン 時間でコンパイルされていない正規表現:63.25ティック

StringBuilder(ユーザー 別)214147 時間:77.125ティック

コンパイルされていない正規表現Tim Hoolihan 時間:147.25ティック

ベンチマークコード...

using System;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Threading;
using System.Text;

static class Program
{
    public static void Main(string[] args)
    {
    long seed = ConfigProgramForBenchmarking();

    Stopwatch sw = new Stopwatch();

    string warmup = "This is   a Warm  up function for best   benchmark results." + seed;
    string input1 = "Hello World,    how are   you           doing?" + seed;
    string input2 = "It\twas\t \tso    nice  to\t\t see you \tin 1950.  \t" + seed;
    string correctOutput1 = "Hello World, how are you doing?" + seed;
    string correctOutput2 = "It\twas\tso nice to\tsee you in 1950. " + seed;
    string output1,output2;

    //warm-up timer function
    sw.Restart();
    sw.Stop();

    sw.Restart();
    sw.Stop();
    long baseVal = sw.ElapsedTicks;

    // InPlace Replace by Felipe Machado but modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin)
    output1 = InPlaceCharArraySpaceOnly (warmup);
    sw.Restart();
    output1 = InPlaceCharArraySpaceOnly (input1);
    output2 = InPlaceCharArraySpaceOnly (input2);
    sw.Stop();
    Console.WriteLine("InPlaceCharArraySpaceOnly : " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    // InPlace Replace by Felipe R. Machado and slightly modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin)
    output1 = InPlaceCharArray(warmup);
    sw.Restart();
    output1 = InPlaceCharArray(input1);
    output2 = InPlaceCharArray(input2);
    sw.Stop();
    Console.WriteLine("InPlaceCharArray: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //Regex with non-compile Tim Hoolihan (https://stackoverflow.com/a/1279874/2352507)
    string cleanedString = 
    output1 = Regex.Replace(warmup, @"\s+", " ");
    sw.Restart();
    output1 = Regex.Replace(input1, @"\s+", " ");
    output2 = Regex.Replace(input2, @"\s+", " ");
    sw.Stop();
    Console.WriteLine("Regex by Tim Hoolihan: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //Regex with compile by Jon Skeet (https://stackoverflow.com/a/1280227/2352507)
    output1 = MultipleSpaces.Replace(warmup, " ");
    sw.Restart();
    output1 = MultipleSpaces.Replace(input1, " ");
    output2 = MultipleSpaces.Replace(input2, " ");
    sw.Stop();
    Console.WriteLine("Regex with compile by Jon Skeet: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //Split And Join by Jon Skeet (https://stackoverflow.com/a/1280227/2352507)
    output1 = SplitAndJoinOnSpace(warmup);
    sw.Restart();
    output1 = SplitAndJoinOnSpace(input1);
    output2 = SplitAndJoinOnSpace(input2);
    sw.Stop();
    Console.WriteLine("Split And Join by Jon Skeet: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //Regex by Brandon (https://stackoverflow.com/a/1279878/2352507
    output1 = Regex.Replace(warmup, @"\s{2,}", " ");
    sw.Restart();
    output1 = Regex.Replace(input1, @"\s{2,}", " ");
    output2 = Regex.Replace(input2, @"\s{2,}", " ");
    sw.Stop();
    Console.WriteLine("Regex by Brandon: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //StringBuilder by user214147 (https://stackoverflow.com/a/2156660/2352507
    output1 = user214147(warmup);
    sw.Restart();
    output1 = user214147(input1);
    output2 = user214147(input2);
    sw.Stop();
    Console.WriteLine("StringBuilder by user214147: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));

    //StringBuilder by fubo (https://stackoverflow.com/a/27502353/2352507
    output1 = fubo(warmup);
    sw.Restart();
    output1 = fubo(input1);
    output2 = fubo(input2);
    sw.Stop();
    Console.WriteLine("StringBuilder by fubo: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));


    //StringBuilder by David S 2013 (https://stackoverflow.com/a/16035044/2352507)
    output1 = SingleSpacedTrim(warmup);
    sw.Restart();
    output1 = SingleSpacedTrim(input1);
    output2 = SingleSpacedTrim(input2);
    sw.Stop();
    Console.WriteLine("StringBuilder(SingleSpacedTrim) by David S: " + (sw.ElapsedTicks - baseVal));
    Console.WriteLine("  Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL "));
    Console.WriteLine("  Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL "));
}

// InPlace Replace by Felipe Machado and slightly modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin)
static string InPlaceCharArray(string str)
{
    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;
    bool lastWasWS = false;
    for (int i = 0; i < len; i++)
    {
        var ch = src[i];
        if (src[i] == '\u0020')
        {
            if (lastWasWS == false)
            {
                src[dstIdx++] = ch;
                lastWasWS = true;
            }
        }
        else
        { 
            lastWasWS = false;
            src[dstIdx++] = ch;
        }
    }
    return new string(src, 0, dstIdx);
}

// InPlace Replace by Felipe R. Machado but modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin)
static string InPlaceCharArraySpaceOnly (string str)
{
    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;
    bool lastWasWS = false; //Added line
    for (int i = 0; i < len; i++)
    {
        var ch = src[i];
        switch (ch)
        {
            case '\u0020': //SPACE
            case '\u00A0': //NO-BREAK SPACE
            case '\u1680': //OGHAM SPACE MARK
            case '\u2000': // EN QUAD
            case '\u2001': //EM QUAD
            case '\u2002': //EN SPACE
            case '\u2003': //EM SPACE
            case '\u2004': //THREE-PER-EM SPACE
            case '\u2005': //FOUR-PER-EM SPACE
            case '\u2006': //SIX-PER-EM SPACE
            case '\u2007': //FIGURE SPACE
            case '\u2008': //PUNCTUATION SPACE
            case '\u2009': //THIN SPACE
            case '\u200A': //HAIR SPACE
            case '\u202F': //NARROW NO-BREAK SPACE
            case '\u205F': //MEDIUM MATHEMATICAL SPACE
            case '\u3000': //IDEOGRAPHIC SPACE
            case '\u2028': //LINE SEPARATOR
            case '\u2029': //PARAGRAPH SEPARATOR
            case '\u0009': //[ASCII Tab]
            case '\u000A': //[ASCII Line Feed]
            case '\u000B': //[ASCII Vertical Tab]
            case '\u000C': //[ASCII Form Feed]
            case '\u000D': //[ASCII Carriage Return]
            case '\u0085': //NEXT LINE
                if (lastWasWS == false) //Added line
                {
                    src[dstIdx++] = ch; //Added line
                    lastWasWS = true; //Added line
                }
            continue;
            default:
                lastWasWS = false; //Added line 
                src[dstIdx++] = ch;
                break;
        }
    }
    return new string(src, 0, dstIdx);
}

static readonly Regex MultipleSpaces =
    new Regex(@" {2,}", RegexOptions.Compiled);

//Split And Join by Jon Skeet (https://stackoverflow.com/a/1280227/2352507)
static string SplitAndJoinOnSpace(string input)
{
    string[] split = input.Split(new char[] { ' '}, StringSplitOptions.RemoveEmptyEntries);
    return string.Join(" ", split);
}

//StringBuilder by user214147 (https://stackoverflow.com/a/2156660/2352507
public static string user214147(string S)
{
    string s = S.Trim();
    bool iswhite = false;
    int iwhite;
    int sLength = s.Length;
    StringBuilder sb = new StringBuilder(sLength);
    foreach (char c in s.ToCharArray())
    {
        if (Char.IsWhiteSpace(c))
        {
            if (iswhite)
            {
                //Continuing whitespace ignore it.
                continue;
            }
            else
            {
                //New WhiteSpace

                //Replace whitespace with a single space.
                sb.Append(" ");
                //Set iswhite to True and any following whitespace will be ignored
                iswhite = true;
            }
        }
        else
        {
            sb.Append(c.ToString());
            //reset iswhitespace to false
            iswhite = false;
        }
    }
    return sb.ToString();
}

//StringBuilder by fubo (https://stackoverflow.com/a/27502353/2352507
public static string fubo(this string Value)
{
    StringBuilder sbOut = new StringBuilder();
    if (!string.IsNullOrEmpty(Value))
    {
        bool IsWhiteSpace = false;
        for (int i = 0; i < Value.Length; i++)
        {
            if (char.IsWhiteSpace(Value[i])) //Comparison with WhiteSpace
            {
                if (!IsWhiteSpace) //Comparison with previous Char
                {
                    sbOut.Append(Value[i]);
                    IsWhiteSpace = true;
                }
            }
            else
            {
                IsWhiteSpace = false;
                sbOut.Append(Value[i]);
            }
        }
    }
    return sbOut.ToString();
}

//David S. 2013 (https://stackoverflow.com/a/16035044/2352507)
public static String SingleSpacedTrim(String inString)
{
    StringBuilder sb = new StringBuilder();
    Boolean inBlanks = false;
    foreach (Char c in inString)
    {
        switch (c)
        {
            case '\r':
            case '\n':
            case '\t':
            case ' ':
                if (!inBlanks)
                {
                    inBlanks = true;
                    sb.Append(' ');
                }
                continue;
            default:
                inBlanks = false;
                sb.Append(c);
                break;
        }
    }
    return sb.ToString().Trim();
}

/// <summary>
/// We want to run this item with max priory to lower the odds of
/// the OS from doing program context switches in the middle of our code. 
/// source:https://stackoverflow.com/a/16157458 
/// </summary>
/// <returns>random seed</returns>
private static long ConfigProgramForBenchmarking()
{
    //prevent the JIT Compiler from optimizing Fkt calls away
    long seed = Environment.TickCount;
    //use the second Core/Processor for the test
    Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
    //prevent "Normal" Processes from interrupting Threads
    Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
    //prevent "Normal" Threads from interrupting this thread
    Thread.CurrentThread.Priority = ThreadPriority.Highest;
    return seed;
}

}

ベンチマークノート:リリースモード、デバッガーなし、i7プロセッサー、平均4回の実行、短い文字列のみをテスト


1
ここで参照されている私の記事を見てうれしい!(私はFelipe Machadoです)BenchmarkDotNetと呼ばれる適切なベンチマークツールを使用して更新しようとしています!すべてのランタイムで実行をセットアップしてみます(DOT NET COREなどがあるので...
Loudenvier

1
@Loudenvier-これでいい仕事。あなたのものは、ほぼ400%で最速でした!.Net Coreは、150〜200%の無料のパフォーマンス向上のようなものです。C ++のパフォーマンスに近づいていますが、コーディングははるかに簡単です。コメントをありがとう。
サンセットクエスト

これはスペースのみを処理し、他の空白文字は処理しません。src [i] == '\ u0020'の代わりにchar.IsWhiteSpace(ch)が必要かもしれません。これはコミュニティによって編集されています。彼らはそれを失敗させましたか?
邪悪な鳩

3

私が使用しているものを共有しています。何か違うものを思いついたようです。私はこれをしばらく使用しており、それは私にとって十分な速度です。それが他の人とどのように積み重なるかはわかりません。私は区切られたファイルライターでそれを使用し、大きなデータテーブルを一度に1つのフィールドで実行します。

    public static string NormalizeWhiteSpace(string S)
    {
        string s = S.Trim();
        bool iswhite = false;
        int iwhite;
        int sLength = s.Length;
        StringBuilder sb = new StringBuilder(sLength);
        foreach(char c in s.ToCharArray())
        {
            if(Char.IsWhiteSpace(c))
            {
                if (iswhite)
                {
                    //Continuing whitespace ignore it.
                    continue;
                }
                else
                {
                    //New WhiteSpace

                    //Replace whitespace with a single space.
                    sb.Append(" ");
                    //Set iswhite to True and any following whitespace will be ignored
                    iswhite = true;
                }  
            }
            else
            {
                sb.Append(c.ToString());
                //reset iswhitespace to false
                iswhite = false;
            }
        }
        return sb.ToString();
    }

2

Jon Skeetが投稿したテストプログラムを使用して、手書きのループをより高速に実行できるかどうかを確認しようとしました。
私は毎回NormalizeWithSplitAndJoinを打つことができますが、入力が1000、5のNormalizeWithRegexを打つだけです。

static string NormalizeWithLoop(string input)
{
    StringBuilder output = new StringBuilder(input.Length);

    char lastChar = '*';  // anything other then space 
    for (int i = 0; i < input.Length; i++)
    {
        char thisChar = input[i];
        if (!(lastChar == ' ' && thisChar == ' '))
            output.Append(thisChar);

        lastChar = thisChar;
    }

    return output.ToString();
}

私はジッターが生成するマシンコードを見ていませんが、問題はStringBuilder.Append()の呼び出しにかかる時間であり、安全を期すには安全でないコードを使用する必要があると思います。

したがって、Regex.Replace()は非常に高速であり、勝つことは困難です!!


2

VB.NET

Linha.Split(" ").ToList().Where(Function(x) x <> " ").ToArray

C#

Linha.Split(" ").ToList().Where(x => x != " ").ToArray();

LINQの力を楽しむ= D


丁度!私にとっても、これは最もエレガントなアプローチです。そうだろうC#のレコード、用:string.Join(" ", myString.Split(' ').Where(s => s != " ").ToArray())
Efrain

1
Splitすべての空白をキャッチしてWhere節を削除するためのマイナーな改善:myString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)
David

1
Regex regex = new Regex(@"\W+");
string outputString = regex.Replace(inputString, " ");

これにより、単語以外のすべての文字がスペースに置き換えられます。そのため、ブラケットや引用符なども必要に応じて置き換えられる可能性があります。
ハーマン、

0

最小のソリューション:

var regExp = / \ s + / g、newString = oldString.replace(regExp、 '');


0

あなたはこれを試すことができます:

    /// <summary>
    /// Remove all extra spaces and tabs between words in the specified string!
    /// </summary>
    /// <param name="str">The specified string.</param>
    public static string RemoveExtraSpaces(string str)
    {
        str = str.Trim();
        StringBuilder sb = new StringBuilder();
        bool space = false;
        foreach (char c in str)
        {
            if (char.IsWhiteSpace(c) || c == (char)9) { space = true; }
            else { if (space) { sb.Append(' '); }; sb.Append(c); space = false; };
        }
        return sb.ToString();
    }

0

置換グループは、複数の空白文字を同じ単一の空白文字で置き換える置換を解決する、よりアプローチを提供します。

    public static void WhiteSpaceReduce()
    {
        string t1 = "a b   c d";
        string t2 = "a b\n\nc\nd";

        Regex whiteReduce = new Regex(@"(?<firstWS>\s)(?<repeatedWS>\k<firstWS>+)");
        Console.WriteLine("{0}", t1);
        //Console.WriteLine("{0}", whiteReduce.Replace(t1, x => x.Value.Substring(0, 1))); 
        Console.WriteLine("{0}", whiteReduce.Replace(t1, @"${firstWS}"));
        Console.WriteLine("\nNext example ---------");
        Console.WriteLine("{0}", t2);
        Console.WriteLine("{0}", whiteReduce.Replace(t2, @"${firstWS}"));
        Console.WriteLine();
    }

2番目の例は単一の\nままですが、受け入れられた回答は行末をスペースに置き換えます。

空白文字の任意の組み合わせを最初の文字と置き換える必要がある場合\kは、パターンから後方参照を削除するだけです。


0

正規表現を使用して、2つ以上の空白を単一のスペースに置き換えることも、良い解決策です。

\ s +」として正規表現パターンを使用しています。

  • \ sは、スペース、タブ、改行、復帰、フォームフィード、または垂直タブと一致します。

  • 「+」は1回以上の発生を示します。

正規表現の例

String blogName = "  Sourav .  Pal.   "

 String nameWithProperSpacing = blogName.replaceAll("\\s+", " ");   
System.out.println( nameWithProperSpacing );

-1

これを行うために組み込まれた方法はありません。あなたはこれを試すことができます:

private static readonly char[] whitespace = new char[] { ' ', '\n', '\t', '\r', '\f', '\v' };
public static string Normalize(string source)
{
   return String.Join(" ", source.Split(whitespace, StringSplitOptions.RemoveEmptyEntries));
}

これにより、先頭と末尾のwhitespceが削除され、内部の空白が1つの空白文字に折りたたまれます。スペースを折りたたむだけの場合は、正規表現を使用したソリューションの方が適しています。それ以外の場合は、このソリューションの方が優れています。(Jon Skeetによる分析を参照してください。)


7
正規表現がコンパイルおよびキャッシュされている場合、分割して結合するよりもオーバーヘッドが多く、中間のガベージ文字列が大量に作成される可能性があります。あなたの方法がより速いと仮定する前に、両方のアプローチの注意深いベンチマークを実行しましたか?
Jon Skeet、

1
ホワイトスペースはここでは宣言されてい
ません

3
オーバーヘッドと言えば、なぜ地球上で電話をかけsource.ToCharArray()て結果を捨てるのですか?
Jon Skeet、

2
そして、呼び出しToCharArray()string.Joinの結果に、唯一の新しい文字列を作成するには...すごい、それはオーバーヘッドのポスト訴えにされるためには、単に顕著です。-1。
Jon Skeet、

1
ああ、がであると仮定するwhitespacenew char[] { ' ' }、入力文字列がスペースで開始または終了している場合、これは誤った結果をもたらします。
Jon Skeet、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.