文字列からすべての空白を削除する効率的な方法?


358

REST APIを呼び出しており、XML応答を受け取ります。それはワークスペース名のリストを返します、そして私は簡単なIsExistingWorkspace()メソッドを書いています。すべてのワークスペースは空白のない連続した文字で構成されているため、特定のワークスペースがリストにあるかどうかを確認する最も簡単な方法は、すべての空白(改行を含む)を削除してこれを実行することです(XMLはWebから受け取った文字列です)リクエスト):

XML.Contains("<name>" + workspaceName + "</name>");

大文字と小文字が区別されることを知っているので、これに依存しています。文字列内のすべての空白を効率的に削除する方法が必要です。RegExとLINQがそれを実行できることは知っていますが、他のアイデアを受け入れます。私は主に速度について心配しています。


6
正規表現を使用してXMLを解析することは、正規表現を使用してHTMLを解析することとほとんど同じです。
dtb

3
@ヘンクホルターマン; 下記の私の回答を参照してください。正規表現は、すべての場合で最速とは限りません。
Henk J Meulekamp 2013年

正規表現は最速ではないようです。文字列から空白を削除するさまざまな方法の結果をまとめました。-概要は以下の回答であるstackoverflow.com/a/37347881/582061
スティアンStandahl

回答:


616

あなたが正規表現を使いたくないと言っていたとしても、これは私が知っている最も速い方法です:

Regex.Replace(XML, @"\s+", "")

1
正規表現を使用することもできますが、それが最速の方法かどうかはわかりません。
Corey Ogburn

1
私はそれがかなり確信している。少なくとも舞台裏では、すべてのキャラクターをチェックする必要があります。これは、線形検索を行っているだけです。
slandau

19
そうじゃないのRegex.Replace(XML, @"\s+", "")
Jan-Peter Vos

61
これを複数回行う予定の場合は、Regexインスタンスを作成して保存します。これにより、毎回作成するオーバーヘッドが節約されます。これは、想像以上にコストがかかります。private static readonly Regex sWhitespace = new Regex(@"\s+"); public static string ReplaceWhitespace(string input, string replacement) { return sWhitespace.Replace(input, replacement); }
誇大広告、2015年

10
RegExの初心者で、この表現の意味に関する説明を探している場合は、\s「任意の空白トークンに一致する」という意味であり、+「1つ以上の先行トークンに一致する」という意味です。また、 RegExrは、実験したい場合にRegEx式の記述を練習するのに最適なWeb​​サイトです。
JRH

181

私は正規表現なしで代替方法を持っています、そしてそれはかなり良いようです。ブランドンモレッツの回答の続きです。

 public static string RemoveWhitespace(this string input)
 {
    return new string(input.ToCharArray()
        .Where(c => !Char.IsWhiteSpace(c))
        .ToArray());
 }

簡単な単体テストでテストしました。

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace1(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = input.RemoveWhitespace();
    }
    Assert.AreEqual(expected, s);
}

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace2(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = Regex.Replace(input, @"\s+", "");
    }
    Assert.AreEqual(expected, s);
}

1,000,000回の試行では、最初のオプション(正規表現なし)は1秒未満(私のマシンでは700 ms)で実行され、2番目のオプションは3.5秒かかります。


40
.ToCharArray()必要はありません。.Where()文字列に直接使用できます。
ProgramFOX 2014年

10
ここで注意してください。正規表現は遅いです...小さな文字列では!米国税法に関するボリュームのデジタル化されたバージョン(〜100万ワード?)があり、反復回数が少ない場合、Regexが圧倒的に優れています。それはより速いものではなく、どのような状況で何を使用すべきかです。あなたはここで方程式の半分を証明しただけです。-1は、テストの後半を証明するまで続きます。その結果、答えは、何を使用する必要があるかについてより多くの洞察を提供します。
Piotr Kula

17
@ppumkin彼は空白のシングルパス削除を求めました。他の処理の複数の反復ではありません。テキスト処理のベンチマークについて、この単一パスの空白を削除して拡張投稿に追加するつもりはありません。
Henk J Meulekamp

1
今回は正規表現に使用しない方が良いとおっしゃっていましたが、理由はお答えできませんでした。
Piotr Kula

2
@ProgramFOX、別の質問で(簡単に見つけることができません)少なくとも一部のクエリでToCharArray.Where()、文字列を直接使用するよりもを使用した方が速いことに気付きました。これはIEnumerable<>、各反復ステップでのオーバーヘッド、およびToCharArray非常に効率的(ブロックコピー)であり、コンパイラーは配列の反復を最適化します。この違いが存在する理由、誰も私を説明できませんでしたが、削除する前に測定してくださいToCharArray()
アベル

87

C#で文字列のreplaceメソッドを試してください。

XML.Replace(" ", string.Empty);

28
タブや改行は削除しません。複数の削除を実行すると、文字列に対して複数のパスが作成されます。
Corey Ogburn

11
slandauとHenkの回答のように、すべての空白を削除しないことに対する反対票。
Matt Sach 2013年

@MattSachなぜすべての空白を削除しないのですか?
Zapnologica

4
@Zapnologicaスペース文字のみを置き換えます。OPは改行の置換も要求しました(これらは空白文字ではありませんが、「空白」文字です)。
Matt Sach

75

私の解決策はSplit and Joinを使用することであり、驚くほど高速です。実際、ここでのトップの回答の中で最速です。

str = string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));

空白を含む単純な文字列での10,000ループのタイミングと新しい行およびタブ

  • 分割/結合= 60ミリ秒
  • linq chararray = 94ミリ秒
  • regex = 437ミリ秒

これをメソッドにラップして意味を持たせることでこれを改善し、それを拡張メソッドにします...

public static string RemoveWhitespace(this string str) {
    return string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
}

3
私はこのソリューションが本当に好きです。LINQ以前の時代から同じようなソリューションを使用しています。私は実際にLINQのパフォーマンスに感銘を受けており、正規表現にも多少驚いています。おそらく、コードが正規表現の場合ほど最適ではなかった可能性があります(たとえば、正規表現オブジェクトをキャッシュする必要があります)。しかし、問題の核心は、データの「品質」が非常に重要になることです。多分長い文字列では、正規表現は他のオプションよりも優れています。楽しいベンチマークになります... :-)
Loudenvier

1
どのようにdefault(string [])==すべての空白文字のリストですか?機能しているように見えますが、どうやって理解できませんか?
Jake Drew

5
あなたが持つ2つのオーバーロードの間に曖昧さを意味@kernowcode string[]char[]?どちらを使用するかを指定するだけですstring.Join("", str.Split((string[])null, StringSplitOptions.RemoveEmptyEntries));。例:。これはdefault、この場合nullも同じように返されるため、この場合の呼び出しです。コンパイラーが選択するオーバーロードを決定するのに役立ちます。したがって、コメントのステートメント「Splitには有効な配列が必要であり、nullには対応しない...」がfalseであるため、私のコメントはfalseです。大したことではありません、ジェイクドリューがこれがどのように機能するかを尋ねたので、言及する価値があると考えました。回答の+1
Frank J

6
アイデアをクール...しかし、次のように私はそれを行うだろう:string.Concat("H \ne llo Wor ld".Split())
michaelkrisper

3
michaelkrisperソリューションは非常に読みやすいです。テストを行ったところ、同じ文字列の10,000回の反復に対して、 'split / join'(162ミリ秒)は 'split / concat'(180ミリ秒)よりも優れたパフォーマンスを示しました。
kernowcode

45

上に構築さHenks答える私は彼の答えといくつかの追加、より最適化され、メソッドを持ついくつかのテストメソッドを作成しました。入力文字列のサイズによって結果が異なることがわかりました。したがって、2つの結果セットでテストしました。最速の方法では、リンクされたソースの方がさらに高速です。しかし、それは安全ではないという特徴があるため、これは省略しました。

長い入力文字列の結果:

  1. InPlaceCharArray:2021 ms(Sunsetquestの回答)-(元のソース
  2. 文字列を分割して結合:4277ms(Kernowcodeの答え
  3. 文字列リーダー:6082 ms
  4. ネイティブ文字を使用するLINQ.IsWhitespace:7357 ms
  5. LINQ:7746 ms(ヘンクの答え
  6. ForLoop:32320ミリ秒
  7. RegexCompiled:37157 ms
  8. 正規表現:42940ミリ秒

短い入力文字列の結果:

  1. InPlaceCharArray:108 ms(Sunsetquestの回答)-(元のソース
  2. 文字列を分割してから結合:294 ms(Kernowcodeの回答
  3. 文字列リーダー:327 ms
  4. ForLoop:343ミリ秒
  5. ネイティブ文字を使用するLINQ.IsWhitespace:624 ms
  6. LINQ:645ms(ヘンクの答え
  7. RegexCompiled:1671ミリ秒
  8. 正規表現:2599ミリ秒

コード

public class RemoveWhitespace
{
    public static string RemoveStringReader(string input)
    {
        var s = new StringBuilder(input.Length); // (input.Length);
        using (var reader = new StringReader(input))
        {
            int i = 0;
            char c;
            for (; i < input.Length; i++)
            {
                c = (char)reader.Read();
                if (!char.IsWhiteSpace(c))
                {
                    s.Append(c);
                }
            }
        }

        return s.ToString();
    }

    public static string RemoveLinqNativeCharIsWhitespace(string input)
    {
        return new string(input.ToCharArray()
            .Where(c => !char.IsWhiteSpace(c))
            .ToArray());
    }

    public static string RemoveLinq(string input)
    {
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }

    public static string RemoveRegex(string input)
    {
        return Regex.Replace(input, @"\s+", "");
    }

    private static Regex compiled = new Regex(@"\s+", RegexOptions.Compiled);
    public static string RemoveRegexCompiled(string input)
    {
        return compiled.Replace(input, "");
    }

    public static string RemoveForLoop(string input)
    {
        for (int i = input.Length - 1; i >= 0; i--)
        {
            if (char.IsWhiteSpace(input[i]))
            {
                input = input.Remove(i, 1);
            }
        }
        return input;
    }

    public static string StringSplitThenJoin(this string str)
    {
        return string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
    }

    public static string RemoveInPlaceCharArray(string input)
    {
        var len = input.Length;
        var src = input.ToCharArray();
        int dstIdx = 0;
        for (int i = 0; i < len; i++)
        {
            var ch = src[i];
            switch (ch)
            {
                case '\u0020':
                case '\u00A0':
                case '\u1680':
                case '\u2000':
                case '\u2001':
                case '\u2002':
                case '\u2003':
                case '\u2004':
                case '\u2005':
                case '\u2006':
                case '\u2007':
                case '\u2008':
                case '\u2009':
                case '\u200A':
                case '\u202F':
                case '\u205F':
                case '\u3000':
                case '\u2028':
                case '\u2029':
                case '\u0009':
                case '\u000A':
                case '\u000B':
                case '\u000C':
                case '\u000D':
                case '\u0085':
                    continue;
                default:
                    src[dstIdx++] = ch;
                    break;
            }
        }
        return new string(src, 0, dstIdx);
    }
}

テスト

[TestFixture]
public class Test
{
    // Short input
    //private const string input = "123 123 \t 1adc \n 222";
    //private const string expected = "1231231adc222";

    // Long input
    private const string input = "123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222";
    private const string expected = "1231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc222";

    private const int iterations = 1000000;

    [Test]
    public void RemoveInPlaceCharArray()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveInPlaceCharArray(input);
        }

        stopwatch.Stop();
        Console.WriteLine("InPlaceCharArray: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveStringReader()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveStringReader(input);
        }

        stopwatch.Stop();
        Console.WriteLine("String reader: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinqNativeCharIsWhitespace()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinqNativeCharIsWhitespace(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ using native char.IsWhitespace: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinq()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinq(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegex()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegex(input);
        }

        stopwatch.Stop();
        Console.WriteLine("Regex: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegexCompiled()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegexCompiled(input);
        }

        stopwatch.Stop();
        Console.WriteLine("RegexCompiled: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveForLoop()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveForLoop(input);
        }

        stopwatch.Stop();
        Console.WriteLine("ForLoop: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [TestMethod]
    public void StringSplitThenJoin()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.StringSplitThenJoin(input);
        }

        stopwatch.Stop();
        Console.WriteLine("StringSplitThenJoin: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }
}

編集:Kernowcodeから素敵な1つのライナーをテストしました。


24

見た目がとても良いので、ただの代替案です:)-注:ヘンクスの回答がこれらの中で最も速いです。

input.ToCharArray()
 .Where(c => !Char.IsWhiteSpace(c))
 .Select(c => c.ToString())
 .Aggregate((a, b) => a + b);

1,000,000ループのテスト "This is a simple Test"

このメソッド= 1.74秒
Regex = 2.58秒
new String(ヘンクス)= 0.82


1
なぜこれは反対票が投じられたのですか?それは完全に許容可能で、要件を満たし、RegExオプションよりも高速で動作し、非常に読みやすいですか?
BlueChippy

4
それははるかに短く書くことができるので:new string(input.Where(c =>!Char.IsWhiteSpace(c))。ToArray());
Bas Smit 2015年

7
本当かもしれない-しかし、答えはまだ立っており、読みやすく、正規表現よりも速く、望ましい結果を生み出します。他の回答の多くはこの回答の後です...したがって、反対投票は意味がありません。
BlueChippy 2015年

2
「0.82」の単位はありますか?それとも、相対的な尺度(82%)ですか?回答をより明確にするために編集できますか?
Peter Mortensen 2017

20

私は Felipe Machado(Richard Robertsonの助けを借りて)によって、CodeProject でこれについての良い記事を見つけました。

彼は10の異なる方法をテストしました。これは最速の安全でないバージョンです...

public static unsafe string TrimAllWithStringInplace(string str) {
    fixed (char* pfixed = str) {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)

            switch (*p) {

                case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':

                case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':

                case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':

                case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':

                case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                    continue;

                default:
                    *dst++ = *p;
                    break;
            }

        return new string(pfixed, 0, (int)(dst - pfixed));
    }
}

そして最速の安全バージョン...

public static string TrimAllWithInplaceCharArray(string str) {

    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;

    for (int i = 0; i < len; i++) {
        var ch = src[i];

        switch (ch) {

            case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':

            case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':

            case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':

            case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':

            case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

            default:
                src[dstIdx++] = ch;
                break;
        }
    }
    return new string(src, 0, dstIdx);
}

また、Stian StandahlによるStack Overflowの優れた独立ベンチマークもいくつかあり、フェリペの関数が次に速い関数よりも約300%速いことも示しています。


これをC ++に変換してみましたが、少し行き詰まっています。なぜ私のポートは失敗するのでしょうか?stackoverflow.com/questions/42135922/…–
ジョンケージ、

2
我慢できない。あなたが参照する記事のコメントセクションを見てください。あなたは「バスケットケースソフトウェア」として私を見つけるでしょう。彼としばらく一緒にこれに取り組んだ。この問題が再び発生したとき、私はこれについて完全に忘れていました。良い思い出をありがとう。:)
リチャード・ロバートソン

1
また、余分なWSだけを削除したい場合はどうすればよいでしょうか。このstackoverflow.com/questions/17770202/…modはどうですか?
トム

最速の方が少し遅い;-)ここでのコンテナのパフォーマンスは文字列の方が優れています(アプリでは4:15から3:55 => 8.5%少なくなりますが、文字列を左にすると3:30 => 21.4%少なくなり、約50%が消費されますこの方法)。したがって、実際のライブ文字列では、ここで使用される(遅い)配列変換と比較して、約40%高速になるはずです。
トム

15

優れたパフォーマンスが必要な場合は、この場合はLINQと正規表現を使用しないでください。パフォーマンスのベンチマークをいくつか行いましたが、文字列の最初と最後から空白を取り除きたい場合、string.Trim()が最終的な関数のようです。

文字列からすべての空白を削除する必要がある場合、次の方法がここに投稿されたすべての方法の中で最も速く機能します。

    public static string RemoveWhitespace(this string input)
    {
        int j = 0, inputlen = input.Length;
        char[] newarr = new char[inputlen];

        for (int i = 0; i < inputlen; ++i)
        {
            char tmp = input[i];

            if (!char.IsWhiteSpace(tmp))
            {
                newarr[j] = tmp;
                ++j;
            }
        }
        return new String(newarr, 0, j);
    }

私はあなたのベンチマークの詳細を知りたいと思っています-私が懐疑的であるというわけではありませんが、Linqに関連するオーバーヘッドに興味があります。それはどれほど悪かったのですか?
Mark Meuer、2014

すべてのテストを再実行したわけではありませんが、これだけ覚えています。Linqに関係するものはすべて、それを持たないものよりもかなり低速でした。文字列/文字関数とコンストラクターの賢い使い方はすべて、Linqが使用された場合、パーセンテージの違いはありませんでした。
JHM、2015年

11

正規表現はやりすぎです。文字列に拡張子を使用するだけです(Henkに感謝)。これは取るに足らないことであり、フレームワークの一部である必要があります。とにかく、これが私の実装です:

public static partial class Extension
{
    public static string RemoveWhiteSpace(this string self)
    {
        return new string(self.Where(c => !Char.IsWhiteSpace(c)).ToArray());
    }
}

これは基本的に不要な回答です(正規表現はやりすぎですが、与えられたものよりも速い解決策です-そしてすでに受け入れられていますか?)
W1ll1amvl

文字列でどのようにLinq拡張メソッドを使用できますか?私が他にどれを使用していないのかSystem.Linq
わかり

これはPCLでは利用できないようです。IEnumerable <char>はMicrosoft String実装では条件付きです...そして、これをサポートしていないProfile259を使用しています:)
GGirard

4

以下は、RegExソリューションの単純な線形代替です。どちらが速いかわかりません。ベンチマークする必要があります。

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

    for (int index = 0; index < input.Length; index++)
    {
        if (!Char.IsWhiteSpace(input, index))
        {
            output.Append(input[index]);
        }
    }
    return output.ToString();
}

3

文字列の空白をスペースで置き換える必要がありましたが、重複するスペースは必要ではありませんでした。たとえば、次のようなものを変換する必要がありました。

"a b   c\r\n d\t\t\t e"

"a b c d e"

私は次の方法を使用しました

private static string RemoveWhiteSpace(string value)
{
    if (value == null) { return null; }
    var sb = new StringBuilder();

    var lastCharWs = false;
    foreach (var c in value)
    {
        if (char.IsWhiteSpace(c))
        {
            if (lastCharWs) { continue; }
            sb.Append(' ');
            lastCharWs = true;
        }
        else
        {
            sb.Append(c);
            lastCharWs = false;
        }
    }
    return sb.ToString();
}

2

私のXML応答は次のようになっていると思います:

var xml = @"<names>
                <name>
                    foo
                </name>
                <name>
                    bar
                </name>
            </names>";

XMLを処理する最良の方法は、LINQ to XMLなどのXMLパーサーを使用することです。

var doc = XDocument.Parse(xml);

var containsFoo = doc.Root
                     .Elements("name")
                     .Any(e => ((string)e).Trim() == "foo");

特定の<name>タグに適切な値があることを確認したら、完了です。ドキュメントの解析にはオーバーヘッドがかかりませんか?
Corey Ogburn

4
もちろん、オーバーヘッドがあります。しかし、正しいという利点があります。たとえば正規表現に基づくソリューションは、正しく行うのがはるかに困難です。LINQ to XMLソリューションが遅すぎると判断した場合は、常により速いものに置き換えることができます。ただし、正しい実装が遅すぎることがわかる前に、最も効率的な実装を探す必要はありません。
dtb

これは私の雇用主のバックエンドサーバーで実行されます。軽量は私が探しているものです。「ちゃんと動く」けれども最適なものは欲しくない。
Corey Ogburn

4
LINQ to XMLは、.NETでXMLを正しく操作するための最も軽量な方法の1つです
dtb

1

ここにさらに別のバリアントがあります:

public static string RemoveAllWhitespace(string aString)
{
  return String.Join(String.Empty, aString.Where(aChar => aChar !Char.IsWhiteSpace(aChar)));
}

他のほとんどのソリューションと同様に、私は徹底的なベンチマークテストを実行していませんが、これは私の目的には十分に機能します。


1

以下を使用できます。

    public static string RemoveWhitespace(this string input)
    {
        if (input == null)
            return null;
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }

これは、上記のヘンクの回答とほぼ同じです。唯一の違いは、を確認することですnull
Corey Ogburn 2016年

はい、nullのチェックは重要です
Tarik BENARAB

1
たぶん、これは彼の答えに対するコメントだったはずです。育ててよかったです。nullオブジェクトで拡張メソッドが呼び出されることを知りませんでした。
Corey Ogburn 2016年

0

別の結果が真実であることがわかりました。すべての空白を1つのスペースに置き換えようとしていますが、正規表現が非常に遅くなりました。

return( Regex::Replace( text, L"\s+", L" " ) );

(C ++ CLIで)私にとって最も最適に機能したのは、次のとおりです。

String^ ReduceWhitespace( String^ text )
{
  String^ newText;
  bool    inWhitespace = false;
  Int32   posStart = 0;
  Int32   pos      = 0;
  for( pos = 0; pos < text->Length; ++pos )
  {
    wchar_t cc = text[pos];
    if( Char::IsWhiteSpace( cc ) )
    {
      if( !inWhitespace )
      {
        if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );
        inWhitespace = true;
        newText += L' ';
      }
      posStart = pos + 1;
    }
    else
    {
      if( inWhitespace )
      {
        inWhitespace = false;
        posStart = pos;
      }
    }
  }

  if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );

  return( newText );
}

最初に各ルーチンを個別に置き換えることにより上記のルーチンを試しましたが、非スペースセクションの部分文字列を実行するように切り替える必要がありました。1,200,000文字の文字列に適用する場合:

  • 上記のルーチンは25秒で完了します
  • 上記のルーチン+ 95秒で個別の文字置換
  • 正規表現は15分後に中止されました。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.