Як замінити кілька пробілів одним пробілом


108

Скажімо, у мене є такий рядок, як:

"Hello     how are   you           doing?"

Я хотів би функцію, яка перетворює кілька просторів в один простір.

Так я отримав би:

"Hello how are you doing?"

Я знаю, що міг би скористатися регулярним виразом або подзвонити

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

Але мені доведеться викликати це кілька разів, щоб переконатися, що всі послідовні пробіли замінені лише одним.

Чи є вже вбудований метод для цього?


Чи можете ви уточнити: чи маєте ви справу лише з пробілами, або "всі" пробілами?
— Джон Скіт

І ви хочете, щоб будь-який простір пробілів перетворився на пробіли?
— Джон Скіт

Я просто мав на увазі, що весь пробіл у серії повинен бути максимум 1
— Метт

1
Можливий дублікат stackoverflow.com/questions/206717 / ...
— Michael Freidgeim

2 речі , щоб розглянути наступні питання: 1. char.IsWhiteSpace включає в себе повернення каретки, переведення рядка і т.д. 2. «пробіл», ймовірно , більш точно протестовані з Char.GetUnicodeCategory (CH) = Globalization.UnicodeCategory.SpaceSeparator
— smirkingman

Відповіді:


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

40
imo, уникаючи регулярного вираження, якщо вам комфортно з ними - передчасна оптимізація
— Тім Хуліхан,

8
Якщо ваша програма не є критичною для часу, вона може дозволити собі 1 мікросекунд обробних витрат.
— Даніель

16
Зауважте, що "\ s" замінює не лише пробіли, а й нові символи рядка.
— Барт Кіерс

12
хороший улов, якщо ви просто хочете, щоб пробіли переключили шаблон на "[] +"
— Тім Хуліхан

9
Чи не слід використовувати "{2,}" замість "+", щоб уникнути заміни одиничних пробілів?
— angularsen

52

Це питання не таке просте, як це показали інші афіші (і як я спочатку вважав, що це так) - тому що питання не зовсім точне, як воно має бути.

Існує різниця між "простором" і "пробілом". Якщо ви маєте на увазі лише пробіли, то вам слід скористатись регулярним виразом " {2,}". Якщо ви маєте на увазі будь-який пробіл, це вже інша справа. Чи слід все пробіли перетворити на пробіли? Що має статися з космосом на початку та в кінці?

Щодо еталону нижче, я припускав, що ви дбаєте лише про пробіли, і ви не хочете нічого робити на окремих просторах, навіть на початку та в кінці.

Зауважте, що правильність майже завжди важливіша, ніж продуктивність. Той факт, що рішення Split / Join видаляє будь-яке провідне проміжне пробіл (навіть лише окремі пробіли), є невірним, що стосується вказаних вами вимог (які, звичайно, можуть бути неповними).

Тест використовує MiniBench .

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

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

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

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

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


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

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

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

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

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

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

Кілька проб:

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

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


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

Тут перше число - це кількість повторень, друге - час, а третє - масштабний бал, 1,0 - найкращий.

Це показує, що принаймні в деяких випадках (включаючи цей) регулярний вираз може перевершити рішення Split / Join, іноді за дуже значним відривом.

Однак якщо ви перейдете на вимогу "все пробіли", то розділитись / приєднатися, як видається, виграє. Як це часто буває, чорт у деталях ...


1
Чудовий аналіз. Отже, виявляється, що ми обидва були в тій чи іншій мірі правильними. Код у моїй відповіді взято з більшої функції, яка має можливість нормалізувати всі пробіли та / або символи управління зсередини рядка та з початку та в кінці.
— Скотт Дорман

1
Щойно вказані вами символи пробілу, у більшості моїх тестів регулярний вираз та розділення / приєднання були приблизно однаковими - S / J мав крихітну, крихітну перевагу, ціною правильності та складності. З цих причин я зазвичай вважаю за краще регулярний вираз. Не зрозумійте мене неправильно - я далекий від фан-регексу, але мені не подобається писати складніші коди заради продуктивності, не по-справжньому спочатку перевіряючи продуктивність.
— Джон Скіт

NormalizeWithSplitAndJoin створить набагато більше сміття, важко сказати, чи справжня проблема отримає більше часу в GC, а потім у відмінні знаки.
— Ян Рінроуз

@IanRingrose Які сорти сміття можна створити?
— Дронз

18

Звичайний експресоїн був би найпростішим способом. Якщо ви правильно пишете регулярний вираз, вам не потрібно буде кілька дзвінків.

Змініть це на це:

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

Моє одне питання @"\s{2,}"полягає в тому, що він не може замінити окремі вкладки та інші символи пробілу Unicode пробілом. Якщо ви збираєтеся замінити 2 вкладки пробілом, вам, ймовірно, слід замінити 1 вкладку пробілом. @"\s+"зробить це за вас.
— Девід Спехт

17

Хоча існуючі відповіді чудові, я хотів би зазначити один підхід, який не працює:

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

Це може циклічно назавжди. Комусь хочеться здогадатися, чому? (Я натрапив на це лише тоді, коли його задавали як питання групи новин кілька років тому ... хтось насправді зіткнувся з цим як проблема.)


Я думаю, що я пам’ятаю, що це питання я задавали деякий час назад. IndexOf ігнорує певні символи, які не замінює. Тож подвійний простір завжди був там, просто ніколи не знімався.
— Брендон

19
Це тому, що IndexOf ігнорує деякі символи Unicode, конкретним винуватцем у цьому випадку є деякий азіатський символ iirc. Хм, нульова ширина, не приєднується, згідно Google.
— ахаукер

Я дізнався, що важкий шлях :( stackoverflow.com/questions/9260693/…
— Антоніо Бакула

Я навчився важкого шляху. Особливо з двома нульовими шинами без ширини (\ u200C \ u200C). IndexOf повертає індекс цього "подвійного простору", але замінити його не замінює. Я думаю, що це тому, що для IndexOf потрібно вказати StringComparsion (Ordinal), щоб він був таким же, як і Замінити. Таким чином, жоден з цих двох не знайде "подвійних пробілів". Більше про StringComparsion docs.microsoft.com/en-us/dotnet/api/…
— Мартін

4

Як уже зазначалося, це легко зробити звичайним виразом. Я просто додам, що ви можете додати до цього .trim (), щоб позбутися провідної / задніх пробілів.


4

Ось рішення, з яким я працюю. Без RegEx і String.Split

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

тож ви можете:

string cleanedString = dirtyString.TrimWhiteSpace();

4

Швидкий додатковий засіб для усунення простору ... Це найшвидший і заснований на місці копії Феліпе Мачадо.

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

Тести ...

InPlaceCharArraySpaceOnly Феліпе Мачадо на CodeProject 2015 та модифікований Sunsetquest для видалення кількох просторів. Час: 3,75 Кліщів

InPlaceCharArray від Felipe Machado 2015 та трохи змінений Sunsetquest для видалення з кількох просторів. Час 6.50 Кліщі (також підтримує вкладки)

SplitAndJoinOnSpace від Джона Скіта . Час: 13,25 тиків

StringBuilder від fubo Час: 13.5 Тик (також підтримує вкладки)

Regex з компілятором Джон Скіт . Час: 17 тиків

StringBuilder від David S 2013 Час: 30,5 тиків

Реджекс з некомпіляцією за часом Брендона : 63,25 тиків

StringBuilder по user214147 Час: 77,125 Кліщів

Regex з не-компіляції Tim Hoolihan Час: 147.25 Кліщів

Код еталону ...

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

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

    Stopwatch sw = new Stopwatch();

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

}

Бенчмарк Примітки: Режим випуску, доданий не-налагоджувач, процесор i7, середня кількість 4 запусків, протестовані лише короткі рядки


1
Приємно бачити мою статтю на яку посилається тут! (Я Феліпе Мачадо) Я збираюся оновити його за допомогою відповідного інструменту орієнтиру під назвою BenchmarkDotNet! Я спробую налаштувати прогони в усі періоди виконання (тепер, коли у нас
— ДОБРЕ НЕ ЧАС

1
@Loudenvier - Приємна робота над цим. Ваш був найшвидшим майже на 400%! .Net Core - це як безкоштовне підвищення продуктивності на 150-200%. Вона наближається до продуктивності c ++, але набагато простіше кодувати. Дякуємо за коментар
— Захід сонця

Це робиться лише пробілами, а не іншими символами пробілу. Може бути, ви хочете char.IsWhiteSpace (ch) замість src [i] == '\ u0020'. Я помічаю, що це відредагувало громаду. Вони його гавкали?
— Злий голуб

3

Я ділюся тим, що використовую, бо, здається, я придумав щось інше. Я використовую це деякий час, і це досить швидко для мене. Я не впевнений, як це протиставляється іншим. Я використовую його в розмежуваному файловому програмі і запускаю великі таблиці даних по одному по одному через нього.

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

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

2

Використовуючи тестову програму, яку розмістив Джон Скіт, я спробував зрозуміти, чи зможу я отримати рукописний цикл для швидшого запуску.
Я можу кожного разу перемогти NormalizeWithSplitAndJoin, але тільки перемогти NormalizeWithRegex з введеннями 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();
}

Я не дивився на машинний код, який створює тремтіння, однак я вважаю, що проблема полягає в часі, який вимагає виклик StringBuilder.Append (), і щоб зробити це набагато краще, знадобиться використання небезпечного коду.

Тож Regex.Replace () дуже швидко і важко перемогти !!


2

VB.NET

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

C #

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

Насолоджуйтесь потужністю LINQ = D


Саме так! Для мене це теж найелегантніший підхід. Отже, для запису в C # це буде:string.Join(" ", myString.Split(' ').Where(s => s != " ").ToArray())
— Efrain

1
Незначне вдосконалення, Splitщоб виловити всю пробіл та зняти Whereпункт:myString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)
— Девід

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

Це замінює всі символи, що не містять слова, на пробіл. Таким чином, він також замінить такі речі, як дужки та цитати тощо, що може бути не тим, що ви хочете.
— Герман

0

Найменше рішення:

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


0

Ви можете спробувати це:

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

0

Змінні групи забезпечують impler підходить дозвіл заміни декількох пробільних символів з однієї єдиними одним:

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

Зверніть увагу, що другий приклад зберігає єдину, \nа прийнята відповідь замінить кінець рядка пробілом.

Якщо вам потрібно замінити будь-яку комбінацію символів пробілу першою, просто видаліть зворотну посилання \kз шаблону.


0

Використання регулярного вираження для заміни двох або більше пробілів на простір також є хорошим рішенням.

Ми використовуємо шаблон регулярного вираження як " \ s + ".

  • \ s відповідає пробілу, вкладці, новій лінії, поверненню каретки, стрічці форми або вертикальній вкладці.

  • '+' говорить про одне або декілька подій.

Приклад Regex

String blogName = "  Sourav .  Pal.   "

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

-1

Для цього не існує вбудованого способу. Ви можете спробувати це:

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

Це видалить провідні та кінцеві пробіли, а також згортає будь-який внутрішній пробіл до одного символу пробілу. Якщо ви дійсно хочете згорнути пробіли, то рішення, що використовують регулярний вираз, краще; інакше це рішення краще. (Див. Аналіз, зроблений Джоном Скітом.)


7
Якщо регулярний вираз компілюється і кешируєтся, я не впевнений , що є більше накладних витрат , ніж розщеплення і приєднання, які можуть створювати навантаження проміжних рядків сміття. Ви зробили ретельні орієнтири обох підходів, перш ніж припускати, що ваш шлях швидший?
— Джон Скіт

1
пробіли тут не задекларовані
— Тім Хуліхан

3
Говорячи про накладні, чому на землі ви дзвоните, source.ToCharArray()а потім викидаєте результат?
— Джон Скіт

2
І закликаючи ToCharArray()результат string.Join, тільки щоб створити нову рядок ... ух, адже це бути в посту, який скаржиться на накладні витрати просто чудовий. -1.
— Джон Скіт

1
О, і припускаючи whitespaceце new char[] { ' ' }, це дасть неправильний результат , якщо вхідний рядок починається або закінчується з простором.
— Джон Скіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.