Cara mengganti beberapa spasi putih dengan satu spasi putih

108

Katakanlah saya memiliki string seperti:

"Hello     how are   you           doing?"

Saya ingin fungsi yang mengubah banyak spasi menjadi satu spasi.

Jadi saya akan mendapatkan:

"Hello how are you doing?"

Saya tahu saya bisa menggunakan regex atau panggilan

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

Tapi saya harus memanggilnya beberapa kali untuk memastikan semua spasi berurutan diganti hanya dengan satu.

Apakah sudah ada metode bawaan untuk ini?

Matt
sumber
Bisakah Anda menjelaskan: apakah Anda hanya berurusan dengan spasi, atau "semua" spasi?
Jon Skeet
Dan apakah Anda ingin ada spasi kosong yang diubah menjadi spasi?
Jon Skeet
Maksud saya semua spasi dalam rangkaian harus paling banyak 1
Matt
1
Kemungkinan duplikat stackoverflow.com/questions/206717/…
Michael Freidgeim
2 hal yang perlu dipertimbangkan: 1. char.IsWhiteSpace menyertakan carriage-return, linefeed, dll. 2. 'whitespace' mungkin lebih akurat diuji dengan Char.GetUnicodeCategory (ch) = Globalization.UnicodeCategory.SpaceSeparator
smirkingman

Jawaban:

196
string cleanedString = System.Text.RegularExpressions.Regex.Replace(dirtyString,@"\s+"," ");
Tim Hoolihan
sumber
40
imo, hindari regex jika Anda merasa nyaman dengan mereka adalah pengoptimalan prematur
Tim Hoolihan
8
Jika aplikasi Anda tidak membutuhkan waktu, aplikasi ini dapat membayar 1 mikrodetik dari overhead pemrosesan.
Daniel
16
Perhatikan bahwa '\ s' tidak hanya menggantikan spasi, tetapi juga karakter baris baru.
Bart Kiers
12
bagus, jika Anda hanya ingin spasi ganti pola ke "[] +"
Tim Hoolihan
9
Bukankah Anda seharusnya menggunakan '{2,}' daripada '+' untuk menghindari penggantian spasi tunggal?
angularsen
52

Pertanyaan ini tidak sesederhana yang dibuat poster lain (dan seperti yang saya yakini semula) - karena pertanyaannya tidak cukup tepat seperti yang seharusnya.

Ada perbedaan antara "spasi" dan "spasi putih". Jika yang Anda maksud hanya spasi, maka Anda harus menggunakan ekspresi reguler " {2,}". Jika yang Anda maksud setiap spasi, itu soal lain. Haruskah semua spasi harus diubah menjadi spasi? Apa yang seharusnya terjadi pada ruang di awal dan akhir?

Untuk patokan di bawah, saya berasumsi bahwa Anda hanya peduli dengan spasi, dan Anda tidak ingin melakukan apa pun pada satu spasi, bahkan di awal dan akhir.

Perhatikan bahwa kebenaran hampir selalu lebih penting daripada kinerja. Fakta bahwa solusi Split / Join menghapus spasi di depan / di belakang (bahkan hanya satu spasi) tidak benar sejauh persyaratan yang Anda tentukan (yang mungkin tidak lengkap, tentu saja).

Tolok ukur menggunakan 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);
    }
}

Beberapa uji coba:

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

Di sini angka pertama adalah jumlah iterasi, yang kedua adalah waktu yang dibutuhkan, dan yang ketiga adalah skor berskala dengan 1,0 sebagai yang terbaik.

Itu menunjukkan bahwa dalam beberapa kasus (termasuk yang satu ini) ekspresi reguler dapat mengungguli solusi Pisahkan / Gabung, terkadang dengan margin yang sangat signifikan.

Namun, jika Anda mengubah untuk "semua spasi" persyaratan, maka Berpisah / Bergabung tidak muncul untuk menang. Seperti yang sering terjadi, iblis berada dalam detail ...

Jon Skeet
sumber
1
Analisis yang bagus. Jadi tampaknya kami berdua benar dalam berbagai tingkatan. Kode dalam jawaban saya diambil dari fungsi yang lebih besar yang memiliki kemampuan untuk menormalkan semua spasi dan / atau karakter kontrol dari dalam string dan dari awal dan akhir.
Scott Dorman
1
Dengan hanya karakter spasi putih yang Anda tentukan, di sebagian besar pengujian saya, regex dan Split / Join hampir sama - S / J memiliki manfaat kecil, kecil, dengan mengorbankan kebenaran dan kerumitan. Untuk alasan tersebut, saya biasanya lebih memilih regex. Jangan salah paham - saya jauh dari fanboy regex, tapi saya tidak suka menulis kode yang lebih kompleks demi performa tanpa benar-benar menguji performanya terlebih dahulu.
Jon Skeet
NormalizeWithSplitAndJoin akan membuat lebih banyak sampah, sulit untuk mengetahui apakah masalah nyata akan terkena lebih banyak waktu GC daripada banchmark.
Ian Ringrose
@IanRingrose Sampah macam apa yang bisa dibuat?
Dronz
18

Expressoin biasa akan menjadi cara termudah. Jika Anda menulis regex dengan cara yang benar, Anda tidak akan memerlukan banyak panggilan.

Ubah menjadi ini:

string s = System.Text.RegularExpressions.Regex.Replace(s, @"\s{2,}", " "); 
Brandon
sumber
Satu masalah saya @"\s{2,}"adalah gagal mengganti tab tunggal dan karakter spasi Unicode lainnya dengan spasi. Jika Anda akan mengganti 2 tab dengan spasi, Anda mungkin harus mengganti 1 tab dengan spasi. @"\s+"akan melakukannya untukmu.
David Specht
17

Meskipun jawaban yang ada baik-baik saja, saya ingin menunjukkan satu pendekatan yang tidak berhasil:

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

Ini bisa berputar selamanya. Ada yang mau menebak kenapa? (Saya baru menemukan ini ketika ditanya sebagai pertanyaan grup berita beberapa tahun yang lalu ... seseorang benar-benar menganggapnya sebagai masalah.)

Jon Skeet
sumber
Saya rasa saya ingat pertanyaan ini ditanyakan beberapa waktu lalu di SO. IndexOf mengabaikan karakter tertentu yang Replace tidak. Jadi ruang ganda itu selalu ada, tidak pernah dihapus.
Brandon
19
Itu karena IndexOf mengabaikan beberapa karakter Unicode, penyebab khusus dalam hal ini adalah beberapa karakter Asia iirc. Hmm, non-joiner lebar nol menurut Google.
ahawker
Saya mempelajarinya dengan cara yang sulit :( stackoverflow.com/questions/9260693/…
Antonio Bakula
Saya belajar dengan cara yang sulit. Khususnya dengan dua Zero Width Non Joiners (\ u200C \ u200C). IndexOf mengembalikan indeks "spasi ganda" ini, tetapi Replace tidak menggantikannya. Saya pikir itu karena untuk IndexOf, Anda perlu menentukan StringComparsion (Ordinal) agar berperilaku sama seperti Ganti. Dengan cara ini, tak satu pun dari keduanya akan menemukan "spasi ganda". Lebih lanjut tentang StringComparsion docs.microsoft.com/en-us/dotnet/api/…
Martin Brabec
4

Seperti yang telah ditunjukkan, ini mudah dilakukan dengan ekspresi reguler. Saya hanya akan menambahkan bahwa Anda mungkin ingin menambahkan .trim () ke dalamnya untuk menghilangkan spasi kosong di depan / di belakang.

MAK
sumber
4

Inilah Solusi yang saya kerjakan. Tanpa RegEx dan 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();
}

jadi kamu bisa:

string cleanedString = dirtyString.TrimWhiteSpace();
fubo
sumber
4

Penghilang spasi ekstra cepat ... Ini yang tercepat dan didasarkan pada salinan di tempat 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);
}

Tolok ukur ...

InPlaceCharArraySpaceOnly oleh Felipe Machado pada CodeProject 2015 dan dimodifikasi oleh Sunsetquest untuk penghapusan multi-ruang. Waktu: 3,75 Kutu

InPlaceCharArray oleh Felipe Machado 2015 dan sedikit dimodifikasi oleh Sunsetquest untuk penghapusan multi-ruang. Waktu 6,50 Ticks (mendukung tab juga)

SplitAndJoinOnSpace oleh Jon Skeet . Waktu: 13.25 Kutu

StringBuilder oleh fubo Waktu: 13.5 Kutu (mendukung tab juga)

Regex dengan kompilasi oleh Jon Skeet . Waktu: 17 Kutu

StringBuilder oleh David S 2013 Waktu: 30.5 Kutu

Regex dengan non-compile oleh Brandon Time: 63.25 Ticks

StringBuilder oleh user214147 Waktu: 77.125 Kutu

Regex dengan Tim Hoolihan non-kompilasi Waktu: 147.25 Kutu

Kode Benchmark ...

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

}

Catatan benchmark: Mode Rilis, tanpa debugger terpasang, prosesor i7, rata-rata 4 proses, hanya string pendek yang diuji

Sunsetquest
sumber
1
Senang melihat artikel saya direferensikan di sini! (Saya Felipe Machado) Saya akan memperbaruinya menggunakan alat patokan yang tepat bernama BenchmarkDotNet! Saya akan mencoba untuk mengatur berjalan di semua runtime (sekarang kita memiliki DOT NET CORE dan sejenisnya ...
Loudenvier
1
@Loudenvier - Kerja bagus untuk ini. Milik Anda adalah yang tercepat dengan hampir 400%! .Net Core seperti peningkatan kinerja 150-200% gratis. Ini semakin mendekati kinerja c ++ tetapi lebih mudah untuk membuat kode. Terima kasih atas komentarnya.
Sunsetquest
Ini hanya spasi, bukan karakter spasi putih lainnya. Mungkin Anda menginginkan char.IsWhiteSpace (ch) daripada src [i] == '\ u0020'. Saya melihat ini telah diedit oleh komunitas. Apakah mereka merusaknya?
Evil Pigeon
3

Saya membagikan apa yang saya gunakan, karena tampaknya saya telah menemukan sesuatu yang berbeda. Saya telah menggunakan ini untuk sementara waktu dan cukup cepat untuk saya. Saya tidak yakin bagaimana itu bisa dibandingkan dengan yang lain. Saya menggunakannya dalam penulis file yang dibatasi dan menjalankan tabel data besar satu per satu melalui itu.

    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();
    }
pengguna214147
sumber
2

Dengan menggunakan program pengujian yang diposting Jon Skeet, saya mencoba melihat apakah saya bisa mendapatkan loop yang ditulis tangan agar berjalan lebih cepat.
Saya bisa mengalahkan NormalizeWithSplitAndJoin setiap saat, tetapi hanya mengalahkan NormalizeWithRegex dengan input 1000, 5.

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

Saya belum melihat kode mesin yang dihasilkan jitter, namun saya berharap masalahnya adalah waktu yang dibutuhkan oleh panggilan ke StringBuilder.Append () dan untuk melakukan yang lebih baik akan memerlukan penggunaan kode yang tidak aman.

Jadi Regex.Replace () sangat cepat dan sulit dikalahkan !!

Ian Ringrose
sumber
2

VB.NET

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

C #

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

Nikmati kekuatan LINQ = D

Patryk Moura
sumber
Persis! Bagi saya ini juga merupakan pendekatan yang paling elegan. Jadi sebagai catatan, dalam C # itu akan menjadi:string.Join(" ", myString.Split(' ').Where(s => s != " ").ToArray())
Efrain
1
Perbaikan kecil pada Splituntuk menangkap semua spasi dan menghapus Whereklausa:myString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)
David
1
Regex regex = new Regex(@"\W+");
string outputString = regex.Replace(inputString, " ");
Michael D.
sumber
Ini menggantikan semua karakter non-kata dengan spasi. Jadi itu juga akan menggantikan hal-hal seperti tanda kurung dan tanda kutip dll, yang mungkin bukan yang Anda inginkan.
Herman
0

Solusi terkecil:

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


sumber
0

Anda bisa mencoba ini:

    /// <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();
    }
LL99
sumber
0

Grup pengganti menyediakan pendekatan impler yang menyelesaikan penggantian beberapa karakter spasi dengan satu karakter yang sama :

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

Harap perhatikan contoh kedua tetap tunggal \nsementara jawaban yang diterima akan menggantikan akhir baris dengan spasi.

Jika Anda perlu mengganti setiap kombinasi karakter spasi dengan yang pertama, hanya menghapus back-referensi \kdari pola.

Dan
sumber
0

Menggunakan ekspresi reguler, untuk mengganti 2 atau lebih spasi putih dengan spasi tunggal, juga merupakan solusi yang baik.

Kami menggunakan pola regex sebagai " \ s + ".

  • \ s cocok dengan spasi, tab, baris baru, carriage return, form feed atau tab vertikal.

  • '+' mengatakan satu atau lebih kemunculan.

Contoh Regex

String blogName = "  Sourav .  Pal.   "

 String nameWithProperSpacing = blogName.replaceAll("\\s+", " ");   
System.out.println( nameWithProperSpacing );
Sourav sobat
sumber
-1

Tidak ada cara bawaan untuk melakukan ini. Anda bisa mencoba ini:

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

Ini akan menghapus whitespce di depan dan di belakang serta menciutkan spasi internal apa pun menjadi satu karakter spasi. Jika Anda benar-benar hanya ingin menciutkan spasi, solusi yang menggunakan ekspresi reguler lebih baik; jika tidak, solusi ini lebih baik. (Lihat analisis yang dilakukan oleh Jon Skeet.)

Scott Dorman
sumber
7
Jika ekspresi reguler dikompilasi dan di-cache, saya tidak yakin itu memiliki lebih banyak overhead daripada pemisahan dan penggabungan, yang dapat membuat banyak string sampah perantara. Sudahkah Anda melakukan benchmark yang cermat dari kedua pendekatan sebelum berasumsi bahwa cara Anda lebih cepat?
Jon Skeet
1
spasi tidak dideklarasikan di sini
Tim Hoolihan
3
Berbicara tentang overhead, mengapa Anda menelepon source.ToCharArray()dan kemudian membuang hasilnya?
Jon Skeet
2
Dan memanggil ToCharArray()hasil string.Join, hanya untuk membuat string baru ... wow, untuk itu berada di pos mengeluh overhead hanya luar biasa. -1.
Jon Skeet
1
Oh, dan asumsinya whitespaceadalah new char[] { ' ' }, ini akan memberikan hasil yang salah jika string input dimulai atau diakhiri dengan spasi.
Jon Skeet