여러 공백을 하나의 공백으로 바꾸는 방법


108

다음과 같은 문자열이 있다고 가정 해 보겠습니다.

"Hello     how are   you           doing?"

여러 공간을 하나의 공간으로 바꾸는 기능을 원합니다.

그래서 나는 얻을 것이다 :

"Hello how are you doing?"

정규식을 사용하거나 전화를 걸 수 있다는 것을 알고 있습니다.

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

그러나 모든 순차 공백이 단 하나로 대체되도록 여러 번 호출해야합니다.

이미 내장 된 방법이 있습니까?


명확하게 설명해 주시겠습니까? 공백 만 처리합니까, 아니면 "모든"공백을 처리합니까?
Jon Skeet

그리고 공백이 아닌 공백을 공백으로 변환 하시겠습니까?
Jon Skeet

일련의 모든 공백은 최대 1이어야 함을 의미했습니다
Matt


2 가지 고려해야 할 : 1. char.IsWhiteSpace은 캐리지 리턴을 포함 라인 피드 등 2. '공백'아마 더 정확하게 Char.GetUnicodeCategory (채널)로 테스트 = Globalization.UnicodeCategory.SpaceSeparator
smirkingman

답변:


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

40
imo, 익숙한 경우 정규식을 피하는 것이 조기 최적화입니다
Tim Hoolihan 2009-08-14

8
애플리케이션이 시간이 중요하지 않은 경우 1 마이크로 초의 처리 오버 헤드를 감당할 수 있습니다.
Daniel

16
'\ s'는 공백뿐만 아니라 새 줄 문자도 대체합니다.
Bart Kiers

12
공백을 원하면 패턴을 "[] +"로 전환하십시오.
Tim Hoolihan 2009-08-14

9
단일 공백을 바꾸지 않으려면 '+'대신 '{2,}'를 사용해야하지 않습니까?
angularsen

52

이 질문은 다른 포스터가 만들어 낸 것만 큼 간단하지 않습니다 (그리고 제가 원래 믿었던 것처럼)-질문이 필요한만큼 정확하지 않기 때문입니다.

"공백"과 "공백"에는 차이가 있습니다. 당신이 경우 에만 공간을 의미, 당신은의 정규식을 사용한다 " {2,}". 공백 을 의미 하는 경우 다른 문제입니다. 모든 공백을 공백으로 변환 해야합니까 ? 시작과 끝에서 공간은 어떻게 되나요?

아래 벤치 마크의 경우 공백에만 관심이 있고 시작과 끝에서도 단일 공백에 대해 아무것도하고 싶지 않다고 가정했습니다.

정확성은 거의 항상 성능보다 중요합니다. 분할 / 결합 솔루션이 선행 / 후행 공백 (단지 단일 공백도 포함)을 제거한다는 사실은 지정된 요구 사항 (물론 불완전 할 수 있음)에 한하면 올바르지 않습니다.

벤치 마크는 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이 가장 좋은 척도입니다.

이는 적어도 일부 경우 (이 경우 포함)에서 정규식 이 분할 / 조인 솔루션을 능가 할 수 있으며 때로는 매우 큰 차이를 보일 수 있음을 보여줍니다.

그러나 "모든 공백"요구 사항으로 변경하면 분할 / 결합 승리하는 것처럼 보입니다. 자주 그렇듯이 악마는 세부 사항에 있습니다 ...


1
훌륭한 분석. 그래서 우리 둘 다 다양한 정도에서 옳은 것 같습니다. 내 대답의 코드는 문자열 내에서 그리고 시작과 끝에서 모든 공백 및 / 또는 제어 문자를 정규화하는 기능을 가진 더 큰 함수에서 가져 왔습니다.
Scott Dorman

1
지정한 공백 문자만으로도 대부분의 테스트에서 정규식과 분할 / 결합은 거의 동일했습니다. S / J는 정확성과 복잡성을 희생하면서 아주 작은 이점을 가졌습니다. 이러한 이유로 저는 일반적으로 정규식을 선호합니다. 오해하지 마십시오. 저는 정규식 팬보이와는 거리가 멀지 만 성능을 먼저 테스트하지 않고 성능을 위해 더 복잡한 코드를 작성하는 것을 좋아하지 않습니다.
Jon Skeet

NormalizeWithSplitAndJoin은 훨씬 더 많은 쓰레기를 생성 할 것입니다. 실제 문제가 banchmark보다 더 많은 GC 시간을 차지할 것인지 말하기는 어렵습니다.
Ian Ringrose

@IanRingrose 어떤 종류의 쓰레기를 만들 수 있습니까?
Dronz

18

정규 표현이 가장 쉬운 방법입니다. 정규식을 올바른 방식으로 작성하면 여러 번 호출 할 필요가 없습니다.

다음과 같이 변경하십시오.

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

내 한 가지 문제 @"\s{2,}"는 단일 탭 및 기타 유니 코드 공백 문자를 공백으로 바꾸지 못한다는 것입니다. 2 개의 탭을 공백으로 바꾸려면 1 개의 탭을 공백으로 바꾸어야합니다. @"\s+"당신을 위해 그렇게 할 것입니다.
David Specht

17

기존 답변은 괜찮지 만 작동 하지 않는 한 가지 접근 방식을 지적하고 싶습니다 .

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

이것은 영원히 반복 될 수 있습니다. 왜 그럴까요? (몇 년 전에 뉴스 그룹 질문으로 질문을 받았을 때만이 문제를 발견했습니다 ... 누군가 실제로 문제로 부딪 혔습니다.)


나는이 질문이 잠시 다시 물었던 것을 기억한다고 생각합니다. IndexOf는 Replace가하지 않는 특정 문자를 무시합니다. 따라서 이중 공간은 항상 거기에 있었고 제거되지 않았습니다.
Brandon

19
IndexOf가 일부 유니 코드 문자를 무시하기 때문입니다.이 경우 특정 오류는 일부 아시아 문자 iirc입니다. 흠, Google에 따르면 너비가 0 인 비결 합자입니다.
ahawker


나는 어려운 길을 배웠다. 특히 두 개의 제로 너비 비 조이너 (\ u200C \ u200C)가 있습니다. IndexOf는이 "이중 공백"의 인덱스를 반환하지만 Replace는이를 대체하지 않습니다. IndexOf의 경우 Replace와 동일하게 동작하도록 StringComparsion (Ordinal)을 지정해야하기 때문이라고 생각합니다. 이렇게하면이 두 가지 모두 "이중 공백"을 찾을 수 없습니다. StringComparsion에 대한 추가 정보 docs.microsoft.com/en-us/dotnet/api/…
Martin

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

빠른 추가 공백 제거기 ... 이것은 가장 빠른 방법이며 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);
}

벤치 마크 ...

InPlaceCharArraySpaceOnly by Felipe Machado on CodeProject 2015 및 Sunsetquest에 의해 다중 공간 제거를 위해 수정되었습니다. 시간 : 3.75 틱

에 의해 InPlaceCharArray 펠리페 마차도 2015 약간 다중 공간 제거 Sunsetquest에 의해 수정. 시간 6.50 틱 (탭도 지원)

Jon Skeet의 SplitAndJoinOnSpace . 시간 : 13.25 틱

Fubo 시간별 StringBuilder : 13.5 틱 (탭도 지원)

Jon Skeet의 컴파일로 정규식 . 시간 : 17 틱

StringBuilder by David S 2013 Time : 30.5 틱

Brandon Time의 컴파일되지 않은 정규식 : 63.25 Ticks

user214147에 의한 StringBuilder 시간 : 77.125 틱

컴파일되지 않은 정규식 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
여기에 참조 된 내 기사를 보니 반갑습니다! (저는 Felipe Machado입니다) BenchmarkDotNet이라는 적절한 벤치 마크 도구를 사용하여 업데이트하려고합니다! 모든 런타임에서 실행을 설정하려고합니다 (이제 DOT NET CORE 등이 있습니다 ...
Loudenvier

1
@Loudenvier-잘하셨습니다. 귀하의 데이터는 거의 400 % 가장 빠릅니다! .Net Core는 150-200 %의 무료 성능 향상과 같습니다. C ++ 성능에 가까워지고 있지만 코딩이 훨씬 쉬워졌습니다. 댓글 주셔서 감사합니다.
Sunsetquest

이것은 다른 공백 문자가 아닌 공백 만 수행합니다. src [i] == '\ u0020'대신 char.IsWhiteSpace (ch)를 원할 수도 있습니다. 커뮤니티에서 수정 한 것 같습니다. 그들은 그것을 지루하게 했습니까?
Evil Pigeon

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

Jon Skeet이 게시 한 테스트 프로그램을 사용하여 손으로 쓴 루프를 더 빨리 실행할 수 있는지 확인했습니다.
매번 NormalizeWithSplitAndJoin을 이길 수 있지만 1000, 5의 입력으로 NormalizeWithRegex 만 이길 수 있습니다.

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

씨#

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)
David

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

대체 그룹은 여러 공백 문자를 동일한 단일 문자로 대체하는 내재적 인 접근 방식을 제공합니다 .

    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

정규 표현식을 사용하여 2 개 이상의 공백을 단일 공백으로 바꾸는 것도 좋은 해결책입니다.

정규식 패턴을 " \ s + "로 사용하고 있습니다.

  • \ s는 공백, 탭, 새 줄, 캐리지 리턴, 용지 공급 또는 수직 탭과 일치합니다.

  • '+'는 하나 이상의 발생을 나타냅니다.

정규식 예

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

이것은 선행 및 후행 공백을 제거하고 내부 공백을 단일 공백 ​​문자로 축소합니다. 정말로 공백 만 축소하려면 정규식을 사용하는 솔루션이 더 좋습니다. 그렇지 않으면이 솔루션이 더 좋습니다. ( Jon Skeet 의 분석을 참조하십시오 .)


7
정규 표현식 컴파일 및 캐시, 내가 만들 수 분할 및 결합,보다 더 많은 오버 헤드가 그 모르겠어요 로드 중간 쓰레기 문자열을. 방법이 더 빠르다고 가정하기 전에 두 가지 접근 방식에 대해 신중한 벤치 마크를 수행 했습니까?
Jon Skeet

1
공백은 여기에서 선언되지 않습니다
Tim Hoolihan

3
오버 헤드에 대해 말하자면, 왜 도대체 전화를 source.ToCharArray()하고 결과를 버리고 있습니까?
Jon Skeet

2
그리고ToCharArray() string.Join의 결과를 호출 하는 것은 새로운 문자열을 생성하기 위해서만 ... 와우, 오버 헤드를 불평하는 포스트에있을 것이기 때문입니다. -1.
Jon Skeet

1
아, 그리고 가정이 whitespacenew char[] { ' ' }이 잘못된 결과를 제공합니다 공백으로 입력 문자열이 시작되거나 끝나는 경우.
Jon Skeet
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.