Cách hiệu quả để loại bỏ TẤT CẢ khoảng trắng khỏi Chuỗi?


358

Tôi đang gọi API REST và đang nhận được phản hồi XML. Nó trả về một danh sách các tên vùng làm việc và tôi đang viết một IsExistingWorkspace()phương thức nhanh . Vì tất cả các không gian làm việc bao gồm các ký tự liền kề không có khoảng trắng, nên tôi giả sử cách dễ nhất để tìm hiểu xem một không gian làm việc cụ thể có trong danh sách là xóa tất cả khoảng trắng (bao gồm cả dòng mới) và thực hiện điều này (XML là chuỗi nhận được từ web yêu cầu):

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

Tôi biết nó phân biệt chữ hoa chữ thường và tôi đang dựa vào đó. Tôi chỉ cần một cách để loại bỏ tất cả khoảng trắng trong một chuỗi một cách hiệu quả. Tôi biết RegEx và LINQ có thể làm điều đó, nhưng tôi mở cho những ý tưởng khác. Tôi chủ yếu chỉ quan tâm đến tốc độ.


6
Phân tích cú pháp XML bằng regex cũng tệ như phân tích HTML bằng regex .
dtb

3
@henk holterman; Xem câu trả lời của tôi dưới đây, regrec dường như không phải là nhanh nhất trong mọi trường hợp.
Henk J Meulekamp

Regex dường như không phải là nhanh nhất. Tôi đã tóm tắt kết quả từ nhiều cách khác nhau để xóa khoảng trắng khỏi chuỗi. Tóm tắt trong một câu trả lời dưới đây - stackoverflow.com/a/37347881/582061
Stian Standahl

Câu trả lời:


616

Đây là cách nhanh nhất mà tôi biết, mặc dù bạn nói rằng bạn không muốn sử dụng các biểu thức thông thường:

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

1
Tôi có thể sử dụng một biểu thức thông thường, tôi chỉ không chắc đó có phải là cách nhanh nhất không.
Corey Ogburn

1
Tôi khá chắc chắn rằng nó là. Ít nhất là đằng sau hậu trường bạn phải kiểm tra từng nhân vật, và đây chỉ là thực hiện tìm kiếm tuyến tính.
slandau

19
Có nên như Regex.Replace(XML, @"\s+", "")vậy không?
Jan-Peter Vos

61
Nếu bạn dự định làm điều này nhiều lần, hãy tạo và lưu trữ một thể hiện Regex. Điều này sẽ tiết kiệm chi phí xây dựng nó mỗi lần, tốn kém hơn bạn nghĩ. private static readonly Regex sWhitespace = new Regex(@"\s+"); public static string ReplaceWhitespace(string input, string replacement) { return sWhitespace.Replace(input, replacement); }
hypehuman

10
Đối với những người mới sử dụng RegEx và đang tìm kiếm một lời giải thích về ý nghĩa của biểu thức này, \scó nghĩa là "khớp với bất kỳ mã thông báo khoảng trắng nào" và +có nghĩa là "khớp với một hoặc nhiều mã thông báo tiến hành". Ngoài ra RegExr là một trang web đẹp để thực hành viết biểu thức RegEx với, nếu bạn muốn thử nghiệm.
jrh

181

Tôi có một cách khác mà không cần regrec, và nó có vẻ hoạt động khá tốt. Đây là phần tiếp theo cho câu trả lời của Brandon Moretz:

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

Tôi đã thử nghiệm nó trong một bài kiểm tra đơn vị đơn giản:

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

Đối với 1.000.000 lần thử, tùy chọn đầu tiên (không có biểu thức chính quy) chạy trong ít hơn một giây (700 ms trên máy của tôi) và lần thứ hai mất 3,5 giây.


40
.ToCharArray()không cần thiết; bạn có thể sử dụng .Where()trực tiếp trên một chuỗi.
Chương trìnhFOX

10
Chỉ cần lưu ý ở đây. Regex chậm hơn ... trên các chuỗi nhỏ! Nếu bạn nói rằng bạn đã có một phiên bản số hóa của Tập về Luật Thuế Hoa Kỳ (~ triệu từ?), Với một số lần lặp lại, Regex là vua, cho đến nay! Nó không phải là những gì nhanh hơn, nhưng những gì nên được sử dụng trong hoàn cảnh nào. Bạn chỉ chứng minh một nửa phương trình ở đây. -1 cho đến khi bạn chứng minh được nửa sau của bài kiểm tra để câu trả lời cung cấp cái nhìn sâu sắc hơn về thời điểm nên sử dụng.
Piotr Kula

17
@ppumkin Anh ấy yêu cầu xóa một khoảng trắng. Không lặp lại nhiều lần xử lý khác. Tôi sẽ không biến việc xóa khoảng trắng đơn này thành một bài đăng mở rộng về xử lý văn bản điểm chuẩn.
Henk J Meulekamp

1
Bạn nói rằng nó không thích sử dụng để regex lần này nhưng không nói lý do tại sao.
Piotr Kula

2
@ProgramFOX, trong một câu hỏi khác (không thể tìm thấy nó) Tôi nhận thấy rằng ít nhất trong một số truy vấn, sử dụng ToCharArraynhanh hơn sử dụng .Where()trực tiếp trên chuỗi. Điều này có liên quan đến chi phí IEnumerable<>trong mỗi bước lặp và ToCharArrayrất hiệu quả (sao chép khối) và trình biên dịch tối ưu hóa việc lặp qua các mảng. Tại sao sự khác biệt này tồn tại, không ai có thể giải thích cho tôi, nhưng đo lường trước khi bạn loại bỏ ToCharArray().
Abel

87

Hãy thử phương pháp thay thế của chuỗi trong C #.

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

28
Không xóa các tab hoặc dòng mới. Nếu tôi thực hiện nhiều lần xóa bây giờ tôi sẽ thực hiện nhiều lần vượt qua chuỗi.
Corey Ogburn

11
Downvote vì không xóa tất cả khoảng trắng, như câu trả lời của slandau và Henk.
Matt Sach

@MattSach tại sao nó không xóa TẤT CẢ khoảng trắng?
Zapnologica

4
@Zapnologica Nó chỉ thay thế các ký tự không gian. OP cũng yêu cầu thay thế các dòng mới (đó là các ký tự "khoảng trắng", mặc dù chúng không phải là ký tự khoảng trắng).
Matt Sach

75

Giải pháp của tôi là sử dụng Split và Tham gia và nó nhanh đến mức đáng ngạc nhiên, trên thực tế là câu trả lời nhanh nhất trong số các câu trả lời hàng đầu ở đây.

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

Thời gian cho 10.000 vòng lặp trên chuỗi đơn giản với khoảng trắng bao gồm các dòng và tab mới

  • chia / tham gia = 60 mili giây
  • linq chararray = 94 mili giây
  • regex = 437 mili giây

Cải thiện điều này bằng cách gói nó trong phương thức để cho nó có ý nghĩa, và cũng biến nó thành một phương thức mở rộng trong khi chúng ta đang ở đó ...

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

3
Tôi thực sự thích giải pháp này, tôi đã sử dụng một giải pháp tương tự kể từ những ngày trước LINQ. Tôi thực sự ấn tượng với hiệu suất của LINQs, và hơi ngạc nhiên với regex. Có thể mã không tối ưu như có thể dành cho regex (ví dụ: bạn sẽ phải lưu trữ đối tượng regex). Nhưng mấu chốt của vấn đề là "chất lượng" của dữ liệu sẽ có vấn đề rất nhiều. Có thể với chuỗi dài, regex sẽ tốt hơn các tùy chọn khác. Đây sẽ là một điểm chuẩn thú vị để thực hiện ... :-)
Lâu đài

1
Làm thế nào để mặc định (chuỗi []) == một danh sách tất cả các ký tự khoảng trắng? Tôi thấy nó hoạt động, nhưng tôi không hiểu làm thế nào?
Jake đã vẽ

5
@kernowcode Ý bạn là sự mơ hồ giữa 2 lần quá tải với string[]char[]? bạn chỉ cần xác định cái nào bạn muốn, ví dụ : string.Join("", str.Split((string[])null, StringSplitOptions.RemoveEmptyEntries));. Đó thực sự là những gì mà cuộc gọi của bạn defaultthực hiện trong trường hợp này vì nó cũng trả về null: nó giúp trình biên dịch quyết định chọn quá tải nào. Do đó nhận xét của tôi vì tuyên bố trong nhận xét của bạn "Tách cần một mảng hợp lệ và null sẽ không làm ..." là sai. Không có vấn đề gì lớn, chỉ nghĩ rằng đáng nói từ khi Jake Drew hỏi làm thế nào điều này làm việc. +1 cho câu trả lời của bạn
Frank J

6
Ý tưởng tuyệt vời ... nhưng tôi sẽ làm như sau:string.Concat("H \ne llo Wor ld".Split())
michaelkrisper

3
giải pháp michaelkrisper là rất dễ đọc. Tôi đã thực hiện một thử nghiệm và 'split / tham gia' (162 mili giây) hoạt động tốt hơn 'split / concat' (180 mili giây) trong 10.000 lần lặp của cùng một chuỗi.
kernowcode

45

Dựa trên câu trả lời của Henks Tôi đã tạo ra một số phương pháp thử nghiệm với câu trả lời của anh ấy và một số phương pháp được thêm vào, tối ưu hóa hơn. Tôi thấy kết quả khác nhau dựa trên kích thước của chuỗi đầu vào. Do đó, tôi đã thử nghiệm với hai bộ kết quả. Trong phương pháp nhanh nhất, nguồn được liên kết thậm chí còn nhanh hơn. Nhưng, vì nó được đặc trưng là không an toàn, tôi đã bỏ nó ra.

Kết quả chuỗi đầu vào dài:

  1. InPlaceCharArray: 2021 ms ( Câu trả lời của Sunsetquest ) - ( Nguồn gốc )
  2. Phân tách chuỗi sau đó tham gia: 4277ms ( câu trả lời của Kernowcode )
  3. Trình đọc chuỗi: 6082 ms
  4. LINQ sử dụng char.IsWhitespace bản địa: 7357 ms
  5. LINQ: 7746 ms ( câu trả lời của Henk )
  6. ForLoop: 32320 ms
  7. RegexCompiled: 37157 ms
  8. Regex: 42940 ms

Kết quả chuỗi đầu vào ngắn:

  1. InPlaceCharArray: 108 ms ( Câu trả lời của Sunsetquest ) - ( Nguồn gốc )
  2. Phân tách chuỗi sau đó tham gia: 294 ms ( câu trả lời của Kernowcode )
  3. Đầu đọc chuỗi: 327 ms
  4. ForLoop: 343 ms
  5. LINQ sử dụng char.IsWhitespace bản địa: 624 ms
  6. LINQ: 645ms ( câu trả lời của Henk )
  7. RegexCompiled: 1671 ms
  8. Regex: 2599 ms

Mã số :

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

Các xét nghiệm :

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

Chỉnh sửa : Đã kiểm tra một lớp lót đẹp từ Kernowcode.


24

Chỉ là một thay thế bởi vì nó trông khá đẹp :) - LƯU Ý: Câu trả lời của Henks là nhanh nhất trong số này.

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

Kiểm tra 1.000.000 vòng trên "This is a simple Test"

Phương pháp này = 1,74 giây
Regex = 2,58 giây
new String(Henks) = 0,82


1
Tại sao điều này bị hạ cấp? Nó hoàn toàn chấp nhận được, đáp ứng các yêu cầu, hoạt động nhanh hơn tùy chọn RegEx và rất dễ đọc?
BlueChippy

4
bởi vì nó có thể được viết ngắn hơn rất nhiều: chuỗi mới (input.Where (c =>! Char.IsWhiteSpace (c)). ToArray ());
Bas Smit

7
Có thể đúng - nhưng câu trả lời vẫn đứng, có thể đọc được, nhanh hơn regex và tạo ra kết quả mong muốn. Nhiều câu trả lời khác là SAU câu này ... do đó, một downvote không có ý nghĩa.
BlueChippy

2
Có một đơn vị cho "0,82"? Hay là một biện pháp tương đối (82%)? Bạn có thể chỉnh sửa câu trả lời của bạn để làm cho nó rõ ràng hơn?
Peter Mortensen

20

Tôi đã tìm thấy một bài viết hay về điều này trên CodeProject của Felipe Machado (với sự giúp đỡ của Richard Robertson )

Ông đã thử nghiệm mười phương pháp khác nhau. Đây là phiên bản không an toàn nhanh nhất ...

public static unsafe string TrimAllWithStringInplace(string str) {
    fixed (char* pfixed = str) {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)

            switch (*p) {

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

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

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

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

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

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

        return new string(pfixed, 0, (int)(dst - pfixed));
    }
}

Và phiên bản an toàn nhanh nhất ...

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

Ngoài ra còn có một số điểm chuẩn độc lập tuyệt vời trên Stack Overflow của Stian Standahl cũng cho thấy chức năng của Felipe nhanh hơn khoảng 300% so với chức năng nhanh nhất tiếp theo.


Tôi đã thử dịch nó sang C ++ nhưng hơi bị kẹt. Bất cứ ý tưởng tại sao cổng của tôi có thể bị lỗi? stackoverflow.com/questions/42135922/ cường
Jon Lồng

2
Tôi không thể cưỡng lại. Nhìn vào phần bình luận của bài viết mà bạn tham khảo. Bạn sẽ tìm thấy tôi là "Phần mềm giỏ". Ông và làm việc với nhau trong một thời gian. Tôi đã hoàn toàn quên mất điều này khi vấn đề này trở lại một lần nữa. Cảm ơn những kỷ niệm đẹp. :)
Richard Robertson

1
Và nếu bạn chỉ muốn loại bỏ thêm WS thì sao? Điều gì về stackoverflow.com/questions/17770202/ Cách mod này?
Tom

Nhanh nhất là chậm hơn một chút ;-) Chuỗi vì container hoàn thiện tốt hơn ở đây (trong ứng dụng 4:15 đến 3:55 => 8,5% ít hơn, nhưng khi chuỗi trái 3:30 => ít hơn 21,4% và trình bày hồ sơ cho thấy khoảng 50% chi tiêu phương pháp này). Vì vậy, trong chuỗi thực trực tiếp nên nhanh hơn khoảng 40% so với chuyển đổi mảng (chậm) được sử dụng ở đây.
Tom

15

Nếu bạn cần hiệu suất tuyệt vời, bạn nên tránh LINQ và các biểu thức chính quy trong trường hợp này. Tôi đã thực hiện một số điểm chuẩn hiệu năng và dường như nếu bạn muốn loại bỏ khoảng trắng từ đầu và cuối chuỗi, chuỗi.Trim () là chức năng cuối cùng của bạn.

Nếu bạn cần loại bỏ tất cả các khoảng trắng từ một chuỗi, phương pháp sau hoạt động nhanh nhất trong tất cả các khoảng trắng đã được đăng ở đây:

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

Tôi tò mò muốn biết chi tiết về điểm chuẩn của bạn - không phải là tôi nghi ngờ, nhưng tôi tò mò về chi phí liên quan đến Linq. Nó tệ đến mức nào?
Mark Meuer

Tôi chưa chạy lại tất cả các bài kiểm tra, nhưng tôi có thể nhớ rất nhiều điều này: Mọi thứ liên quan đến Linq chậm hơn rất nhiều so với mọi thứ mà không có nó. Tất cả việc sử dụng thông minh các hàm chuỗi / char và hàm tạo không tạo ra sự khác biệt phần trăm nếu Linq được sử dụng.
JHM

11

Regex là quá mức cần thiết; chỉ cần sử dụng phần mở rộng trên chuỗi (cảm ơn Henk). Điều này là tầm thường và nên là một phần của khung. Dù sao, đây là triển khai của tôi:

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

về cơ bản đây là một câu trả lời không cần thiết (regex là quá mức cần thiết, nhưng là một giải pháp nhanh hơn so với đưa ra - và nó đã được chấp nhận chưa?)
W1ll1amvl

Làm thế nào bạn có thể sử dụng các phương thức mở rộng Linq trên một chuỗi? Không thể tìm ra cách sử dụng tôi đang thiếu người khác hơnSystem.Linq
GGirard

Ok có vẻ như điều này không có sẵn trong PCL, IEnumerable <char> có điều kiện trong triển khai Microsoft String ... Và tôi đang sử dụng Profile259 không hỗ trợ điều này :)
GGirard 18/2/2016

4

Đây là một thay thế tuyến tính đơn giản cho giải pháp RegEx. Tôi không chắc cái nào nhanh hơn; bạn phải điểm chuẩn nó.

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

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

3

Tôi cần thay thế khoảng trắng trong một chuỗi bằng khoảng trắng, nhưng không trùng lặp khoảng trắng. ví dụ: tôi cần chuyển đổi một cái gì đó như sau:

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

đến

"a b c d e"

Tôi đã sử dụng phương pháp sau

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

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

2

Tôi giả sử phản hồi XML của bạn trông như thế này:

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

Cách tốt nhất để xử lý XML là sử dụng trình phân tích cú pháp XML, chẳng hạn như LINQ sang XML :

var doc = XDocument.Parse(xml);

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

Khi tôi xác minh rằng thẻ <name> cụ thể có giá trị phù hợp, tôi đã hoàn tất. Sẽ không phân tích tài liệu có một số chi phí?
Corey Ogburn

4
Chắc chắn, nó có một số chi phí. Nhưng nó có lợi ích là chính xác. Một giải pháp dựa trên regex khó khăn hơn nhiều để có được quyền. Nếu bạn xác định rằng giải pháp LINQ to XML quá chậm, bạn luôn có thể thay thế bằng giải pháp nhanh hơn. Nhưng bạn nên tránh săn lùng để thực hiện hiệu quả nhất trước khi bạn biết rằng cái đúng là quá chậm.
dtb

Điều này sẽ được chạy trong các máy chủ phụ trợ của chủ nhân của tôi. Nhẹ là những gì tôi đang tìm kiếm. Tôi không muốn một cái gì đó "chỉ hoạt động" nhưng là tối ưu.
Corey Ogburn

4
LINQ to XML là một trong những cách nhẹ nhất để hoạt động chính xác với XML trong .NET
dtb

1

Đây là một biến thể khác:

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

Như với hầu hết các giải pháp khác, tôi chưa thực hiện các bài kiểm tra điểm chuẩn toàn diện, nhưng điều này hoạt động đủ tốt cho mục đích của tôi.


1

Chúng tôi có thể sử dụng:

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

Điều này gần như chính xác như câu trả lời của Henk ở trên. Sự khác biệt duy nhất là bạn kiểm tra null.
Corey Ogburn

Có, kiểm tra null là nhập khẩu
Tarik BENARAB

1
Có lẽ đây chỉ là một nhận xét về câu trả lời của anh ấy. Tôi rất vui vì bạn đã đưa nó lên mặc dù. Tôi không biết các phương thức mở rộng có thể được gọi trên các đối tượng null.
Corey Ogburn

0

Tôi đã tìm thấy kết quả khác nhau là đúng. Tôi đang cố gắng thay thế tất cả các khoảng trắng bằng một khoảng trống và regex cực kỳ chậm.

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

Điều làm việc tối ưu nhất đối với tôi (trong C ++ cli) là:

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

Tôi đã thử thói quen trên trước bằng cách thay thế từng ký tự riêng biệt, nhưng phải chuyển sang thực hiện các chuỗi con cho các phần không phải khoảng trắng. Khi áp dụng cho chuỗi 1.200.000 ký tự:

  • thói quen trên được thực hiện trong 25 giây
  • thói quen trên + thay thế ký tự riêng trong 95 giây
  • regex đã hủy bỏ sau 15 phút.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.