source

String에서 모든 공백을 제거하는 효율적인 방법

nicesource 2023. 4. 14. 21:55
반응형

String에서 모든 공백을 제거하는 효율적인 방법

REST API의 XML을 사용합니다.이름 되고 작업영역 이름 목록을 쓰고 IsExistingWorkspace() 가 있는지 은 모든 공백하고 이를요청에서 입니다).모든 워크스페이스는 공백이 없는 연속된 문자로 구성되므로 목록에 특정 워크스페이스가 있는지 확인하는 가장 쉬운 방법은 모든 공백(새로운 줄 포함)을 제거하고 다음을 수행하는 것입니다(XML은 웹 요청에서 받은 문자열임).

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

대소문자가 구분된다는 걸 알고 있고, 거기에 의존하고 있어요.문자열의 모든 공백을 효율적으로 제거하는 방법만 있으면 됩니다.RegEx와 LINQ가 할 수 있다는 것은 알지만, 다른 아이디어에 대해서는 준비가 되어 있습니다.나는 단지 속도에만 관심이 있다.

정규 표현을 사용하고 싶지 않다고 하셨지만, 이것이 제가 아는 가장 빠른 방법입니다.

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

코멘트에서 @hypehuman을 crediting하여 여러 번 이 작업을 수행할 예정이라면 Regex 인스턴스를 생성하여 저장합니다.이렇게 하면 매번 건설하는 데 드는 오버헤드를 줄일 수 있어 생각보다 비용이 많이 듭니다.

private static readonly Regex sWhitespace = new Regex(@"\s+");
public static string ReplaceWhitespace(string input, string replacement) 
{
    return sWhitespace.Replace(input, replacement);
}

regexp를 사용하지 않고 다른 방법을 사용할 수 있는데, 성능이 상당히 좋은 것 같습니다.Brandon Moretz의 답변에 대한 연속입니다.

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

간단한 유닛 테스트로 테스트했습니다.

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace1(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = input.RemoveWhitespace();
    }
    Assert.AreEqual(expected, s);
}

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace2(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = Regex.Replace(input, @"\s+", "");
    }
    Assert.AreEqual(expected, s);
}

1,000,000번의 시행에 대해 첫 번째 옵션(regexp 없음)은 1초 이내에 실행되며(머신에서는 700밀리초), 두 번째 옵션은 3.5초 걸립니다.

C# 의 문자열 치환 방법을 사용해 보겠습니다.

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

이 솔루션은 Split and Join(분할 및 참여)을 사용하는 것입니다.이 솔루션은 놀라울 정도로 빠른 속도로, 실제로 여기서 가장 빠른 답변입니다.

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

새로운 행과 탭에 공백이 있는 단순한 문자열의 10,000루프 타이밍

  • split/interval = 60 밀리초
  • linq charararray = 94 밀리초
  • regex = 437 밀리초

의미를 부여하기 위해 포장하는 방법으로 개선하고, 동시에 연장하는 방법도 만들어 주세요.

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

Henks의 답변을 바탕으로 나는 그의 답변으로 몇 가지 테스트 방법과 더 최적화된 추가 방법을 만들었다.입력 문자열의 크기에 따라 결과가 다르다는 것을 알았습니다.따라서 저는 두 가지 결과 세트로 테스트했습니다.가장 빠른 방법에서는 링크된 소스가 훨씬 더 빠른 방법을 가집니다.하지만 안전하지 않다는 특성이 있기 때문에 생략했습니다.

긴 입력 문자열 결과:

  1. InPlaceCharArray: 2021 ms (Sunsetquest의 답변) - (원래 소스)
  2. 문자열 분할 후 결합: 4277ms(Kernowcode의 답변)
  3. 문자열 리더: 6082 ms
  4. 네이티브 문자를 사용하는 LINQ.Is White 공간: 7357 밀리초
  5. LINQ: 7746 ms (Henk의 답변)
  6. ForLoop: 32320 밀리초
  7. Regex 컴파일 완료: 37157 밀리초
  8. 정규식: 42940 밀리초

짧은 입력 문자열 결과:

  1. InPlaceCharArray: 108 ms (Sunsetquest의 답변) - (원래 소스)
  2. 문자열 분할 후 결합: 294 ms (Kernowcode의 답변)
  3. 문자열 리더: 327 밀리초
  4. ForLoop: 343 밀리초
  5. 네이티브 문자를 사용하는 LINQ.Is White 공간: 624 ms
  6. LINQ: 645ms (Henk의 답변)
  7. Regex Compiled: 1671 ms
  8. 정규식: 2599 밀리초

코드:

public class RemoveWhitespace
{
    public static string RemoveStringReader(string input)
    {
        var s = new StringBuilder(input.Length); // (input.Length);
        using (var reader = new StringReader(input))
        {
            int i = 0;
            char c;
            for (; i < input.Length; i++)
            {
                c = (char)reader.Read();
                if (!char.IsWhiteSpace(c))
                {
                    s.Append(c);
                }
            }
        }

        return s.ToString();
    }

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

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

    public static string RemoveRegex(string input)
    {
        return Regex.Replace(input, @"\s+", "");
    }

    private static Regex compiled = new Regex(@"\s+", RegexOptions.Compiled);
    public static string RemoveRegexCompiled(string input)
    {
        return compiled.Replace(input, "");
    }

    public static string RemoveForLoop(string input)
    {
        for (int i = input.Length - 1; i >= 0; i--)
        {
            if (char.IsWhiteSpace(input[i]))
            {
                input = input.Remove(i, 1);
            }
        }
        return input;
    }

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

    public static string RemoveInPlaceCharArray(string input)
    {
        var len = input.Length;
        var src = input.ToCharArray();
        int dstIdx = 0;
        for (int i = 0; i < len; i++)
        {
            var ch = src[i];
            switch (ch)
            {
                case '\u0020':
                case '\u00A0':
                case '\u1680':
                case '\u2000':
                case '\u2001':
                case '\u2002':
                case '\u2003':
                case '\u2004':
                case '\u2005':
                case '\u2006':
                case '\u2007':
                case '\u2008':
                case '\u2009':
                case '\u200A':
                case '\u202F':
                case '\u205F':
                case '\u3000':
                case '\u2028':
                case '\u2029':
                case '\u0009':
                case '\u000A':
                case '\u000B':
                case '\u000C':
                case '\u000D':
                case '\u0085':
                    continue;
                default:
                    src[dstIdx++] = ch;
                    break;
            }
        }
        return new string(src, 0, dstIdx);
    }
}

테스트:

[TestFixture]
public class Test
{
    // Short input
    //private const string input = "123 123 \t 1adc \n 222";
    //private const string expected = "1231231adc222";

    // Long input
    private const string input = "123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222";
    private const string expected = "1231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc222";

    private const int iterations = 1000000;

    [Test]
    public void RemoveInPlaceCharArray()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveInPlaceCharArray(input);
        }

        stopwatch.Stop();
        Console.WriteLine("InPlaceCharArray: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveStringReader()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveStringReader(input);
        }

        stopwatch.Stop();
        Console.WriteLine("String reader: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinqNativeCharIsWhitespace()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinqNativeCharIsWhitespace(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ using native char.IsWhitespace: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinq()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinq(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegex()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegex(input);
        }

        stopwatch.Stop();
        Console.WriteLine("Regex: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegexCompiled()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegexCompiled(input);
        }

        stopwatch.Stop();
        Console.WriteLine("RegexCompiled: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveForLoop()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveForLoop(input);
        }

        stopwatch.Stop();
        Console.WriteLine("ForLoop: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [TestMethod]
    public void StringSplitThenJoin()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.StringSplitThenJoin(input);
        }

        stopwatch.Stop();
        Console.WriteLine("StringSplitThenJoin: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }
}

편집: Kernowcode에서 멋진 라이너를 테스트했습니다.

꽤 좋아 보이기 때문에 그냥 대안일 뿐이다:)-메모: 헨크스의 답변은 이것들 중 가장 빠르다.

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

1,"This is a simple Test"

메서드 =1' = 1.74초'
) = 2.58초(표준)
new String(Henks) = 0.82µ

Felipe Machado(Richard Robertson의 도움을 받아)의 Code Project에 대한 멋진 글을 발견했습니다.

그는 10가지 다른 방법을 시험했다.이게 가장 빠른 안전 버전이야

public static string TrimAllWithInplaceCharArray(string str) {

    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;

    for (int i = 0; i < len; i++) {
        var ch = src[i];

        switch (ch) {

            case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':

            case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':

            case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':

            case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':

            case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

            default:
                src[dstIdx++] = ch;
                break;
        }
    }
    return new string(src, 0, dstIdx);
}

그리고 가장 안전하지 않은 버전은...(Sunsetquest 2021년 5월 26일 일부 설명)

public static unsafe void RemoveAllWhitespace(ref string str)
{
    fixed (char* pfixed = str)
    {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)
        {
            switch (*p)
            {
                case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':
                case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':
                case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':
                case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':
                case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

                default:
                    *dst++ = *p;
                    break;
            }
        }

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

Stian Standahl의 Stack Overflow에는 Felipe의 기능이 두 번째로 빠른 기능보다 약 300% 더 빠른 독립 벤치마크도 있습니다.그리고 제가 수정한 것은 이 방법을 사용했습니다.

뛰어난 퍼포먼스를 필요로 하는 경우는, 이 경우는 LINQ 와 정규 표현을 사용하지 말아 주세요.퍼포먼스 벤치마킹을 실시했습니다만, 스트링의 선두와 말미에서 공백 공간을 떼어내고 싶은 경우는, 스트링을 선택해 주세요.Trim()은 궁극의 기능입니다.

문자열에서 모든 공백을 제거해야 할 경우 여기에 게시된 모든 방법 중에서 다음 방법이 가장 효과적입니다.

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

Regex는 과잉입니다.스트링에 확장자를 사용하세요(Henk씨 감사합니다).이것은 사소하고 프레임워크의 일부였어야 했다.어쨌든, 제 실장은 다음과 같습니다.

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

공간을 없애기 위해 많은 분들이 오시는 것 같아요.:

string s = "my string is nice";
s = s.replace(" ", "");

다음은 RegEx 솔루션의 단순한 선형 대안입니다.어느 것이 더 빠른지 잘 모르겠어요. 벤치마크를 해야 할 것 같아요.

static string RemoveWhitespace(string input)
{
    StringBuilder output = new StringBuilder(input.Length);

    for (int index = 0; index < input.Length; index++)
    {
        if (!Char.IsWhiteSpace(input, index))
        {
            output.Append(input[index]);
        }
    }
    return output.ToString();
}

문자열의 공백을 공백으로 대체해야 했지만 중복된 공백으로 대체해서는 안 되었습니다. 예를 들어 다음과 같이 변환해야 했습니다.

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

로.

"a b c d e"

나는 다음과 같은 방법을 사용했다.

private static string RemoveWhiteSpace(string value)
{
    if (value == null) { return null; }
    var sb = new StringBuilder();

    var lastCharWs = false;
    foreach (var c in value)
    {
        if (char.IsWhiteSpace(c))
        {
            if (lastCharWs) { continue; }
            sb.Append(' ');
            lastCharWs = true;
        }
        else
        {
            sb.Append(c);
            lastCharWs = false;
        }
    }
    return sb.ToString();
}

XML 응답은 다음과 같습니다.

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

XML을 처리하는 가장 좋은 방법은 LINQ에서 XML로 등의 XML 파서를 사용하는 것입니다.

var doc = XDocument.Parse(xml);

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

다음 중 하나를 사용할 수 있습니다.

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

Linq 를 사용하면, 다음과 같이 판독 가능한 방법을 쓸 수 있습니다.

    public static string RemoveAllWhitespaces(this string source)
    {
        return string.IsNullOrEmpty(source) ? source : new string(source.Where(x => !char.IsWhiteSpace(x)).ToArray());
    }

다음은 또 다른 변형입니다.

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

다른 대부분의 솔루션과 마찬가지로 완전한 벤치마크 테스트를 실행하지는 않았지만, 이 테스트는 제 목적에 충분히 부합합니다.

나는 다른 결과가 사실이라는 것을 알았다.모든 공백을 하나의 공백으로 바꾸려고 하는데 정규식이 너무 느렸어요.

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

(C++ CLI에서) 나에게 가장 최적으로 작용한 것은 다음과 같습니다.

String^ ReduceWhitespace( String^ text )
{
  String^ newText;
  bool    inWhitespace = false;
  Int32   posStart = 0;
  Int32   pos      = 0;
  for( pos = 0; pos < text->Length; ++pos )
  {
    wchar_t cc = text[pos];
    if( Char::IsWhiteSpace( cc ) )
    {
      if( !inWhitespace )
      {
        if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );
        inWhitespace = true;
        newText += L' ';
      }
      posStart = pos + 1;
    }
    else
    {
      if( inWhitespace )
      {
        inWhitespace = false;
        posStart = pos;
      }
    }
  }

  if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );

  return( newText );
}

먼저 각 문자를 개별적으로 교체하여 위의 루틴을 시도했지만, 공백이 아닌 부분에 대해서는 서브스트링으로 전환해야 했습니다.1,200,000 문자 문자열에 적용할 경우:

  • 위의 루틴은 25초 안에 완료됩니다.
  • 위 루틴 + 95초 후 별도의 문자 바꾸기
  • regex가 15분 후에 중단되었습니다.

문자열에서 모든 공백을 제거하는 간단한 방법(예제)이 첫 번째 문자열입니다.

String.Concat(example.Where(c => !Char.IsWhiteSpace(c))

언급URL : https://stackoverflow.com/questions/6219454/efficient-way-to-remove-all-whitespace-from-string

반응형