447

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

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

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

4

17 に答える 17

745

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

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

コメントに@hypehumanをクレジットします。これを複数回行う予定がある場合は、正規表現インスタンスを作成して保存します。これにより、毎回構築するオーバーヘッドが節約されます。これは、想像以上に費用がかかります。

private static readonly Regex sWhitespace = new Regex(@"\s+");
public static string ReplaceWhitespace(string input, string replacement) 
{
    return sWhitespace.Replace(input, replacement);
}
于 2011-06-02T19:38:29.887 に答える
219

正規表現を使用しない別の方法がありますが、パフォーマンスはかなり良いようです。ブランドン・モレッツの答えの続きです。

 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回の試行では、最初のオプション(regexpなし)は1秒未満(私のマシンでは700ミリ秒)で実行され、2番目のオプションは3.5秒かかります。

于 2013-01-29T19:58:52.750 に答える
104

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

XML.Replace(" ", string.Empty);
于 2011-06-02T19:43:27.810 に答える
58

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

長い入力文字列の結果:

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

短い入力文字列の結果:

  1. InPlaceCharArray: 108 ms ( Sunsetquest の回答) - (元のソース)
  2. 文字列の分割と結合: 294 ミリ秒 ( Kernowcode の回答)
  3. 文字列リーダー: 327 ミリ秒
  4. ForLoop: 343 ミリ秒
  5. ネイティブ char.IsWhitespace を使用した LINQ: 624 ミリ秒
  6. LINQ: 645ms (ヘンクの回答)
  7. 正規表現のコンパイル: 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 の素敵なワンライナーをテストしました。

于 2016-05-20T13:23:54.207 に答える
31

非常に見栄えが良いため、単なる代替手段です:)-注:Henksの回答は、これらの中で最も迅速です。

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 秒正規表現
= 2.58 秒
new String(ヘンクス) = 0.82 秒

于 2013-11-28T05:28:18.190 に答える
24

これについては、Felipe Machado による CodeProjectに関するすばらしい記事を見つけました ( Richard Robertsonの協力を得て)

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

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

そして最速の安全でないバージョン... (Sunsetquest 5/26/2021 によるいくつかの改善)

public static unsafe void RemoveAllWhitespace(ref 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;
            }
        }

        uint* pi = (uint*)pfixed;
        ulong len = ((ulong)dst - (ulong)pfixed) >> 1;
        pi[-1] = (uint)len;
        pfixed[len] = '\0';
    }
}

また、Stian Standahl によるスタック オーバーフローに関するいくつかの優れた独立したベンチマークもあり、Felipe の関数が 2 番目に高速な関数よりも約 300% 高速であることも示されています。また、私が修正したものについては、このトリックを使用しました。

于 2016-05-21T21:25:52.523 に答える
11

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

public static partial class Extension
{
    public static string RemoveWhiteSpace(this string self)
    {
        return new string(self.Where(c => !Char.IsWhiteSpace(c)).ToArray());
    }
}
于 2014-10-18T00:11:22.470 に答える
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();
}
于 2011-06-02T19:50:51.300 に答える
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();
}
于 2014-10-05T00:42:23.213 に答える
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");
于 2011-06-02T19:40:28.280 に答える
2

以下を使用できます。

    public static string RemoveWhitespace(this string input)
    {
        if (input == null)
            return null;
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }
于 2016-06-20T14:59:52.437 に答える
1

これはさらに別の変種です:

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

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

于 2015-06-18T19:49:43.783 に答える
0

さまざまな結果が真実であることを発見しました。すべての空白を単一のスペースに置き換えようとしていますが、正規表現は非常に遅かったです。

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

最初に各文字を個別に置き換えて上記のルーチンを試しましたが、スペース以外のセクションの部分文字列に切り替える必要がありました。120万文字列に適用する場合:

  • 上記のルーチンは 25 秒で完了します
  • 上記のルーチン + 別の文字置換を 95 秒で
  • 正規表現は 15 分後に中止されました。
于 2015-02-02T21:53:01.877 に答える