Dize TÜM boşluk kaldırmak için verimli bir yol?


361

Bir REST API çağırıyorum ve bir XML yanıtı geri alıyorum. Çalışma alanı adlarının bir listesini döndürür ve hızlı bir IsExistingWorkspace()yöntem yazıyorum . Tüm çalışma alanları boşluk içermeyen bitişik karakterler içerdiğinden, belirli bir çalışma alanının listede olup olmadığını bulmanın en kolay yolunun tüm boşlukları (yeni satırlar dahil) kaldırmak ve bunu yapmaktır (XML web'den alınan dizedir) istek):

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

Büyük / küçük harfe duyarlı olduğunu biliyorum ve buna güveniyorum. Sadece verimli bir dize tüm boşluk kaldırmak için bir yol gerekir. RegEx ve LINQ'nun bunu yapabileceğini biliyorum, ama başka fikirlere de açığım. Çoğunlukla hız konusunda endişeliyim.


6
XML'yi normal ifade ile ayrıştırmak, HTML'yi normal ifade ile ayrıştırmak kadar kötüdür .
dtb

3
@henk holterman; Aşağıdaki cevabımı gör, regexp her durumda en hızlı gibi görünmüyor.
Henk J Meulekamp

Regex hiç de hızlı görünmüyor. Bir dize boşluk kaldırmak için birçok farklı yoldan sonuçları özetledim. Özet aşağıdaki cevapta - stackoverflow.com/a/37347881/582061
Stian Standahl

Yanıtlar:


618

Bu, düzenli ifadeler kullanmak istemediğinizi söylemiş olsanız bile, bildiğim en hızlı yoldur:

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

1
Düzenli bir ifade kullanabilirim, bunun en hızlı yol olup olmadığından emin değilim.
Corey Ogburn

1
Eminim öyle. En azından perde arkasında her karakteri kontrol etmelisiniz ve bu sadece doğrusal bir arama yapıyor.
slandau

19
Olmamalı mı Regex.Replace(XML, @"\s+", "")?
Jan-Peter Vos

61
Bunu bir kereden fazla yapmayı planlıyorsanız, bir Regex örneği oluşturun ve saklayın. Bu, her seferinde inşa etme yükünü kurtaracaktır, bu da düşündüğünüzden daha pahalıdır. private static readonly Regex sWhitespace = new Regex(@"\s+"); public static string ReplaceWhitespace(string input, string replacement) { return sWhitespace.Replace(input, replacement); }
hypehuman

10
RegEx'te yeni olanlar ve bu ifadenin ne anlama geldiğine dair bir açıklama arayanlar, \s"herhangi bir boşluk işaretiyle eşleştir" +anlamına gelir ve "devam eden belirtecin bir veya daha fazlasıyla eşleşir" anlamına gelir. Ayrıca RegExr , denemek isterseniz , RegEx ifadeleri yazma alıştırması yapmak için güzel bir web sitesidir.
jrh

181

Regexp olmadan alternatif bir yol var ve oldukça iyi bir performans gibi görünüyor. Brandon Moretz cevabının devamıdır:

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

Basit bir birim testinde test ettim:

[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 denemede ilk seçenek (regexp olmadan) bir saniyeden daha kısa sürede (makinemde 700 ms) çalışır ve ikincisi 3.5 saniye sürer.


40
.ToCharArray()gerekli değil; .Where()doğrudan bir dizede kullanabilirsiniz .
ProgramFOX

10
Sadece buraya not etmek için. Regex küçük dizelerde daha yavaştır! ABD Vergi Yasası üzerinde bir cildin (~ milyon kelime?) Sayısallaştırılmış bir versiyonuna sahip olduğunuzu söylüyorsanız, bir avuç yineleme ile Regex açık ara kral! Daha hızlı olan şey değil, hangi durumda ne kullanılmalıdır. Burada denklemin sadece yarısını kanıtladın. -1, testin ikinci yarısını kanıtlayana kadar, cevabın ne zaman kullanılması gerektiğine dair daha fazla bilgi sağlar.
Piotr Kula

17
@ppumkin Boşluğun tek geçişli kaldırılmasını istedi. Diğer işlemlerin çoklu yinelemeleri değil. Kıyaslama metin işleme hakkında genişletilmiş bir yazı içine bu tek geçiş boşluk kaldırma yapmak değil.
Henk J Meulekamp

1
Bu sefer normal ifadeyi kullanmamayı tercih ettiğini söyledin ama nedenini söylemedin.
Piotr Kula

2
@ProgramFOX, farklı bir soruda (kolayca bulamıyorum) En azından bazı sorgularda, ToCharArraykullanımın .Where()doğrudan dizede kullanmaktan daha hızlı olduğunu fark ettim . Bunun IEnumerable<>her yineleme adımında ek yük ile bir ilgisi vardır ve ToCharArrayçok verimli (blok-kopya) ve derleyici diziler üzerinde yinelemeyi optimize eder. Bu fark neden var, kimse beni açıklayamadı, ama kaldırmadan önce ölçün ToCharArray().
Abel

87

C # dizesinin değiştirme yöntemini deneyin.

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

28
Sekmeleri veya yeni satırları kaldırmaz. Ben şimdi birden fazla kaldırırsanız ben dize üzerinden birden fazla geçiş yapıyorum.
Corey Ogburn

11
Slandau ve Henk'in cevaplarının yaptığı gibi, tüm boşlukları kaldırmamaya çalışın.
Matt Sach

@MattSach TÜM boşlukları neden kaldırmıyor?
Zapnologica

4
@Zapnologica Yalnızca boşluk karakterlerinin yerini alır. OP, satırsonlarının da değiştirilmesini istedi (boşluk karakteri olmasa bile "boşluk" karakterleri).
Matt Sach

76

Benim çözümüm Split and Join kullanmak ve şaşırtıcı derecede hızlı, aslında en iyi cevapların en hızlısı.

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

Whitespace inc yeni satırlar ve sekmelerle basit dizede 10.000 döngü zamanlamaları

  • böl / birleştir = 60 milisaniye
  • linq chararray = 94 milisaniye
  • normal ifade = 437 milisaniye

Bunu anlam vermek için bir yöntemle tamamlayarak geliştirin ve aynı zamanda onu bir genişletme yöntemi haline getirin ...

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

3
Bu çözümü gerçekten seviyorum, LINQ öncesi günlerden beri benzer bir çözüm kullanıyorum. Aslında LINQs performansından etkilendim ve normal ifade ile biraz şaşırdım. Belki de kod normal ifade için olabildiğince optimal değildi (örneğin normal ifade nesnesini önbelleğe almanız gerekir). Ancak sorunun kaynağı, verilerin "kalitesinin" çok önemli olacağıdır. Belki uzun dizelerle normal ifade diğer seçeneklerden daha iyi performans gösterir. Gerçekleştirmek için eğlenceli bir kriter olacak ... :-)
Loudenvier

1
Default (string []) == tüm boşluk karakterlerinin listesi nasıl? Çalıştığını görüyorum, ama nasıl olduğunu anlamıyorum?
Jake Drew

5
@kernowcode 2 aşırı yüklenme string[]ve ile arasındaki belirsizliği mi kastediyorsunuz char[]? sen sadece örn istediğiniz hangisini belirtmek gerekir: string.Join("", str.Split((string[])null, StringSplitOptions.RemoveEmptyEntries));. Aslında defaultbu durumda yaptığınız çağrı da budur çünkü geri döner null: derleyiciye hangi aşırı yükü seçeceğine karar vermesine yardımcı olur. Bu nedenle benim yorumumda "Split geçerli bir dizi gerekiyor ve boş yapmaz ..." deyimindeki deyim yanlış olduğundan. Önemli değil, sadece Jake Drew bunun nasıl çalıştığını sorduğundan bahsetmeye değer. Cevabınız için +1
Frank J

6
Harika bir fikir ... ama şu şekilde yaparım:string.Concat("H \ne llo Wor ld".Split())
michaelkrisper

3
michaelkrisper çözeltisi çok okunabilir. Bir test yaptım ve 'split / join' (162 milisaniye), aynı dizenin 10.000 yinelemesi için 'split / concat' (180 milisaniye) 'den daha iyi performans gösterdi.
kernowcode

45

Bina Henks cevap Onun cevabını ve bazı ilave, daha optimize, yöntemlerle bazı test yöntemleri oluşturduk. Sonuçları girdi dizesinin boyutuna göre farklı buldum. Bu nedenle, iki sonuç kümesi ile test yaptım. En hızlı yöntemde, bağlı kaynağın daha da hızlı bir yolu vardır. Ancak, güvensiz olarak nitelendirildiği için bunu dışarıda bıraktım.

Uzun giriş dizesi sonuçları:

  1. InPlaceCharArray: 2021 ms ( Sunsetquest'in cevabı ) - ( Orijinal kaynak )
  2. String split then join: 4277ms ( Kernowcode'un yanıtı )
  3. Tel okuyucu: 6082 ms
  4. Yerel karakter kullanan LINQ. Boşluk: 7357 ms
  5. LINQ: 7746 ms ( Henk'in cevabı )
  6. Döngü için: 32320 ms
  7. Normal Düzenlenen: 37157 ms
  8. Normal İfade: 42940 ms

Kısa giriş dizesi sonuçları:

  1. InPlaceCharArray: 108 ms ( Sunsetquest'in yanıtı ) - ( Orijinal kaynak )
  2. Dize bölme sonra birleştirme: 294 ms ( Kernowcode'un yanıtı )
  3. Tel okuyucu: 327 ms
  4. Döngü için: 343 ms
  5. Yerel karakter kullanarak LINQ. Boşluk: 624 ms
  6. LINQ: 645ms (Henk'in cevabı )
  7. Düzenli: 1671 ms
  8. Normal ifade: 2599 ms

Kod :

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

Testler :

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

Düzenleme : Güzel bir tek astar Kernowcode denendi.


24

Sadece bir alternatif çünkü oldukça güzel görünüyor :) - NOT: Henks cevap bunların en hızlısı.

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

1.000.000 döngüyü test etme "This is a simple Test"

Bu yöntem = 1,74 saniye Normal İfade
= 2,58 saniye
new String(Henks) = 0,82


1
Bu neden reddedildi? Mükemmel kabul edilebilir, gereksinimleri karşılar, RegEx seçeneğinden daha hızlı çalışır ve çok okunabilir mi?
BlueChippy

4
çünkü çok daha kısa yazılabilir: new string (input.Where (c =>! Char.IsWhiteSpace (c)). ToArray ());
Bas Smit

7
Doğru olabilir - ama cevap hala duruyor, okunabilir, normalden daha hızlı ve istenen sonucu veriyor. Diğer cevapların çoğu bu sorudan SONRA ... bu nedenle bir aşağı oy mantıklı değil.
BlueChippy

2
"0.82" için bir birim var mı? Yoksa göreceli bir önlem mi (% 82)? Cevabınızı daha açık hale getirmek için düzenleyebilir misiniz?
Peter Mortensen

20

Felipe Machado'nun CodeProject hakkında güzel bir yazı buldum ( Richard Robertson'ın yardımıyla )

On farklı yöntemi test etti. Bu en güvenli olmayan versiyon ...

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

Ve en hızlı güvenli versiyon ...

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 tarafından Stack Overflow'da, Felipe'nin fonksiyonunun bir sonraki en hızlı fonksiyondan yaklaşık% 300 daha hızlı olduğunu gösteren bazı güzel bağımsız kriterler de var.


Ben C ++ bu çeviri denedim ama biraz sıkışmış. Bağlantı noktamın neden başarısız olabileceği hakkında bir fikrin var mı? stackoverflow.com/questions/42135922/…
Jon Cage

2
Direnem. Başvurduğunuz makalenin yorumlar bölümüne bakın. Beni "Basketcase Yazılımı" olarak bulacaksınız. Bir süre bunun üzerinde birlikte çalıştı. Bu sorun tekrar ortaya çıktığında bunu tamamen unutmuştum. Güzel anılar için teşekkürler. :)
Richard Robertson

1
Ve yalnızca fazladan WS'yi kaldırmak isterseniz ne olur? Peki ya stackoverflow.com/questions/17770202/… mod?
Tom

En hızlı biraz daha yavaştır ;-) Burada daha iyi performans gösteren dize Bu method). Yani gerçek canlı dize burada kullanılan (yavaş) dizi dönüşüm karşılaştırıldığında yaklaşık% 40 daha hızlı olmalıdır.
Tom

15

Mükemmel performansa ihtiyacınız varsa, bu durumda LINQ ve düzenli ifadelerden kaçınmalısınız. Bazı performans karşılaştırması yaptım ve dize başından ve sonuna kadar beyaz boşluk bırakmak istiyorsanız, string.Trim () nihai işleviniz gibi görünüyor.

Bir dizeden tüm beyaz boşlukları soymanız gerekiyorsa, aşağıdaki yöntem burada yayınlananların en hızlısıdır:

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

Kıyaslamalarınızın ayrıntılarını bilmek isterdim - şüpheci değilim, ama Linq ile ilgili yükü merak ediyorum. Ne kadar kötüydü?
Mark Meuer

Tüm testleri tekrar yapmadım, ama bunu çok hatırlıyorum: Linq'in dahil olduğu her şey onsuz her şeyden çok daha yavaştı. Linq kullanıldığında, string / char fonksiyonlarının ve kurucularının akıllıca kullanımı hiçbir yüzde fark yaratmadı.
JHM

11

Regex aşırı dolu; sadece ipte uzantı kullanın (teşekkürler Henk). Bu önemsizdir ve çerçevenin bir parçası olmalıydı. Her neyse, işte benim uygulama:

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

Bu temelde gereksiz bir cevaptır (regex aşırı kiloludur, ancak verilenden daha hızlı bir çözümdür - ve zaten kabul edilmiş mi?)
W1ll1amvl

Bir dizede Linq uzantı yöntemlerini nasıl kullanabilirsiniz? Hangi kullanımdan başkalarını System.Linq
özlediğimi anlayamıyorum

Tamam bu PCL'de mevcut değil gibi görünüyor, IEnumerable <char> Microsoft String uygulamasında koşullu ... Ve bunu desteklemiyor Profile259 kullanıyorum :)
GGirard

4

İşte RegEx çözümüne basit bir doğrusal alternatif. Hangisinin daha hızlı olduğundan emin değilim; kıyaslamak zorunda kalacaksınız.

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

Bir dize boşluk ile boşluk yerine yinelenen boşlukları değiştirmek gerekiyordu. örneğin, aşağıdaki gibi bir şeyi dönüştürmek gerekiyordu:

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

için

"a b c d e"

Aşağıdaki yöntemi kullandım

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 yanıtınızın şöyle göründüğünü varsayıyorum:

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

XML işlemenin en iyi yolu, LINQ to XML gibi bir XML ayrıştırıcı kullanmaktır :

var doc = XDocument.Parse(xml);

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

Belirli bir <name> etiketinin uygun değere sahip olduğunu doğruladıktan sonra, işim bitti. Belgeyi ayrıştırmanın ek yükü olmaz mı?
Corey Ogburn

4
Tabii, biraz yükü var. Ancak doğru olma avantajı vardır. Normal ifadeye dayanan bir çözümün doğru bir şekilde yapılması çok daha zordur. LINQ to XML çözümünün çok yavaş olduğunu belirlerseniz, bunu her zaman daha hızlı bir şeyle değiştirebilirsiniz. Ancak doğru olanın çok yavaş olduğunu bilmeden önce en verimli uygulama için avlanmaktan kaçınmalısınız.
dtb

Bu işverenimin arka uç sunucularında çalışacak. Aradığım şey hafif. "Sadece işe yarayan" ama optimal olan bir şey istemiyorum.
Corey Ogburn

4
XML'den LINQ, .NET'te XML ile doğru şekilde çalışmanın en hafif yollarından biridir
dtb

1

İşte başka bir varyant:

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

Diğer çözümlerin çoğunda olduğu gibi, kapsamlı kıyaslama testleri yapmadım, ancak bu benim amacım için yeterince iyi çalışıyor.


1

Kullanabiliriz:

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

Bu neredeyse Henk'in yukarıdaki cevabı ile hemen hemen aynı. Tek fark kontrol etmeniz null.
Corey Ogburn

Evet, null olup olmadığını kontrol edin import
Tarik BENARAB

1
Belki de bu onun cevabı hakkında bir yorum olmalıydı. Yine de getirdiğine sevindim. Boş nesnelere uzantı yöntemleri çağrılabilir bilmiyordum.
Corey Ogburn

0

Doğru olmak için farklı sonuçlar buldum. Tüm boşlukları tek bir boşlukla değiştirmeye çalışıyorum ve normal ifade son derece yavaştı.

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

Benim için en uygun olanı (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 );
}

Her bir karakteri ayrı ayrı değiştirerek ilk önce yukarıdaki rutini denedim, ancak boşluk olmayan bölümler için alt dizeler yapmak zorunda kaldım. 1.200.000 karakter dizesine başvururken:

  • yukarıdaki rutin 25 saniyede yapılır
  • 95 saniye içinde yukarıdaki rutin + ayrı karakter değiştirme
  • normal ifade 15 dakika sonra iptal edildi.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.