Làm cách nào để thay thế nhiều khoảng trắng bằng một khoảng trắng trong C #?


439

Làm cách nào tôi có thể thay thế nhiều khoảng trắng trong một chuỗi chỉ bằng một khoảng trắng trong C #?

Thí dụ:

1 2 3  4    5

sẽ là:

1 2 3 4 5

1
một cỗ máy trạng thái có thể dễ dàng làm điều đó, nhưng nó có thể quá mức nếu bạn chỉ cần nó để xóa khoảng trống
Adrian

Tôi đã thêm một điểm chuẩn về các cách khác nhau để thực hiện điều này trong một câu hỏi trùng lặp stackoverflow.com/a/37592018/582061 . Regex không phải là cách nhanh nhất để làm điều này.
Stian Standahl

Câu trả lời:


468
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");

2
Tôi đã sao chép và dán nó và nó hoạt động. Tôi thực sự không thích REgex nhưng lần này nó cứu mạng tôi.
Pokus

9
@Craig một bình luận sẽ đủ, IMO. // Khối này thay thế nhiều khoảng trắng bằng một ... :)
paulwhit

6
Thực sự, RegEx là quá mức cần thiết cho việc này.
Joel Coehoorn

11
@Joel: Không thể đồng ý. Tôi thực sự chắc chắn rằng cách này hiệu quả hơn so với của bạn cho các chuỗi đủ lớn và có thể được thực hiện trong một dòng duy nhất. Quá mức cần thiết?
Konrad Rudolph

24
Mã của @Oscar Joel không phải là một vòng lặp đơn giản thông qua tất cả các ký tự! Đó là một vòng lặp lồng nhau ẩn có trường hợp xấu nhất bậc hai. Ngược lại, biểu thức chính quy này là tuyến tính, chỉ xây dựng một chuỗi duy nhất (= giảm đáng kể chi phí phân bổ so với mã của Joel) và hơn nữa, công cụ có thể tối ưu hóa địa ngục khỏi nó (thành thật mà nói, tôi nghi ngờ rằng regex .NET là đủ thông minh cho việc này nhưng về mặt lý thuyết, biểu thức chính quy này có thể được thực hiện với giá rẻ đến mức nó không còn buồn cười nữa, nó chỉ cần một DFA với ba trạng thái, mỗi trạng thái chuyển tiếp và không có thông tin bổ sung).
Konrad Rudolph

623

Tôi thích sử dụng:

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

Vì nó sẽ bắt chạy bất kỳ loại khoảng trắng nào (ví dụ: tab, dòng mới, v.v.) và thay thế chúng bằng một khoảng trắng.


43
Sửa đổi nhẹ: Regex.Replace (nguồn, @ "(\ s) \ s +", "$ 1"); Điều này sẽ trả về loại khoảng trắng đầu tiên được tìm thấy. Vì vậy, nếu bạn có 5 tab, nó sẽ trả về một tab. Có ai đó thích điều này.
FB ten Kate

@radistao Liên kết của bạn là để thay thế chuỗi Javascript, không phải cho C #.
Shiva

1
@Shiva, / \ s \ s + / là một câu lệnh regex chuẩn POSIX và có thể được chuyển đổi / sử dụng trong bất kỳ ngôn ngữ nào bằng cú pháp riêng
radistao

4
Theo tinh thần của giải pháp của @ FBtenKate: Regex.Replace (nguồn, @ "(\ s) \ 1+", "$ 1"); sẽ thay thế nhiều ký tự liên tiếp giống hệt nhau bằng một ký tự duy nhất.
François Beaune

1
để xóa các khoảng trắng hàng đầu và dấu, bạn nên sử dụng hàm Trim () với hàm này, như var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
Harish Nayak

50
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));

6
Đây là có thể đọc được nhiều hơn regex, tôi thích nó hơn vì tôi không cần phải tìm hiểu một số cú pháp khác
Michael Bahig

9
Tôi thích nó vì nó không cần Regex
AleX_

3
Điều này sẽ không hiệu quả đối với các chuỗi lớn.
DarcyThomas

3
Điều này cũng loại bỏ không gian hàng đầu và dấu.
Matzi

1
Tôi thích câu trả lời này là tốt. Người cố vấn cũ của tôi đã từng nói "bất cứ khi nào bạn gặp vấn đề bạn nghĩ rằng bạn cần Regex để giải quyết, thì ... bây giờ bạn đã gặp phải HAI vấn đề" <wink>
William Madonna Jr.

38

Tôi nghĩ câu trả lời của Matt là tốt nhất, nhưng tôi không tin nó hoàn toàn đúng. Nếu bạn muốn thay thế dòng mới, bạn phải sử dụng:

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);

4
RegexOptions.Multiline thay đổi ý nghĩa của ^ và $ để chúng khớp với đầu và cuối của mỗi dòng ($ = \ n), thay vì toàn bộ chuỗi nhiều dòng. Vì \ s tương đương với [\ f \ n \ r \ t \ v] nên các dòng mới sẽ được thay thế ngay cả khi tùy chọn Multiline bị tắt.
SushiGuy

1
Câu trả lời của Matt đã bao gồm điều này. Tôi 'tin' 30 người chỉ bịt mắt bỏ phiếu đã trả lời câu trả lời này :)
123iamking

26

Một cách tiếp cận khác sử dụng LINQ:

 var list = str.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));
 str = string.Join(" ", list);

23

Nó đơn giản hơn nhiều so với tất cả:

while(str.Contains("  ")) str = str.Replace("  ", " ");

23
Điều này sẽ kém hiệu quả hơn nhiều so với regex "{2,}" nếu chuỗi chứa chuỗi 3 hoặc nhiều khoảng trắng.
Jan Goyvaerts

2
@JanGoyvaerts: Ngay cả với 10 khoảng trắng, regex vẫn chậm hơn khi tôi thực hiện một bài kiểm tra nhanh và bẩn. Điều đó đang được nói, nó chỉ mất một chuỗi con khổng lồ đầy không gian để tiêu diệt hoàn toàn hiệu suất của vòng lặp while. Để công bằng, tôi đã sử dụng Tôi đã sử dụng RegexOptions.Compiled, thay vì Regex.Replace chậm hơn.
Brian

5
RegexOptions.Compiled thêm rất nhiều chi phí biên dịch regex vào IL. Không sử dụng nó trừ khi ứng dụng của bạn sẽ sử dụng regex thường xuyên đủ hoặc trên các chuỗi đủ lớn để tốc độ kết hợp tăng làm giảm tốc độ biên dịch giảm.
Jan Goyvaerts

Đây là một ví dụ về mã cực kỳ kém hiệu quả. CƯỜI LỚN.
pcbabu

1
@pcbabu Nó không tệ như nhiều trường hợp. Các Replace()phương pháp sẽ xử lý tất cả các lần xuất hiện của hai khoảng trống trong một chuỗi nhất định, vì vậy chúng tôi không lặp (và tái phân bổ một chuỗi toàn) cho mỗi thể hiện của không gian cặp trong chuỗi. Một phân bổ mới sẽ xử lý tất cả chúng. Chúng tôi chỉ chạy lại vòng lặp khi có 3 khoảng trống trở lên cùng nhau, điều này có khả năng xảy ra hiếm hơn đối với nhiều nguồn đầu vào. Nếu bạn có thể hiển thị nó trở thành một vấn đề đối với dữ liệu của bạn, thì hãy viết máy trạng thái để đẩy từng ký tự vào một trình tạo chuỗi mới.
Joel Coehoorn

21

Regex có thể khá chậm ngay cả với các tác vụ đơn giản. Điều này tạo ra một phương thức mở rộng có thể được sử dụng từ bất kỳ string.

    public static class StringExtension
    {
        public static String ReduceWhitespace(this String value)
        {
            var newString = new StringBuilder();
            bool previousIsWhitespace = false;
            for (int i = 0; i < value.Length; i++)
            {
                if (Char.IsWhiteSpace(value[i]))
                {
                    if (previousIsWhitespace)
                    {
                        continue;
                    }

                    previousIsWhitespace = true;
                }
                else
                {
                    previousIsWhitespace = false;
                }

                newString.Append(value[i]);
            }

            return newString.ToString();
        }
    }

Nó sẽ được sử dụng như vậy:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."


11

Đối với những người không thích Regex, đây là một phương pháp sử dụng StringBuilder:

    public static string FilterWhiteSpaces(string input)
    {
        if (input == null)
            return string.Empty;

        StringBuilder stringBuilder = new StringBuilder(input.Length);
        for (int i = 0; i < input.Length; i++)
        {
            char c = input[i];
            if (i == 0 || c != ' ' || (c == ' ' && input[i - 1] != ' '))
                stringBuilder.Append(c);
        }
        return stringBuilder.ToString();
    }

Trong các thử nghiệm của tôi, phương pháp này trung bình nhanh hơn 16 lần với một chuỗi các chuỗi có kích thước từ nhỏ đến trung bình rất lớn, so với một Regex được biên dịch tĩnh. So với một Regex không được biên dịch hoặc không tĩnh, điều này thậm chí còn nhanh hơn.

Hãy nhớ rằng nó không xóa các khoảng trắng ở đầu hoặc cuối, chỉ có nhiều lần xuất hiện như vậy.


Nếu bạn muốn kiểm tra xem nhân vật có phải là khoảng trắng không, và không chỉ là khoảng trắng, hãy xem câu trả lời của tôi dưới đây .
Riệp

8

Bạn chỉ có thể làm điều này trong một giải pháp dòng!

string s = "welcome to  london";
s.Replace(" ", "()").Replace(")(", "").Replace("()", " ");

Bạn có thể chọn dấu ngoặc khác (hoặc thậm chí các ký tự khác) nếu bạn muốn.


1
Bạn phải đảm bảo chuỗi của bạn không có "()" hoặc ") (" trong đó. Hoặc "wel()come to london)("trở thành "wel come to london". Bạn có thể thử sử dụng nhiều dấu ngoặc. Vì vậy, sử dụng ((((()))))thay vì ())))))(((((thay vì )(. Nó vẫn hoạt động. chuỗi chứa ((((()))))hoặc )))))(((((, điều này sẽ thất bại.
nmit026

7

Đây là một phiên bản ngắn hơn, chỉ nên được sử dụng nếu bạn chỉ làm điều này một lần, vì nó tạo ra một thể hiện mới của Regexlớp mỗi khi nó được gọi.

temp = new Regex(" {2,}").Replace(temp, " "); 

Nếu bạn không quá quen thuộc với các biểu thức thông thường, đây là một lời giải thích ngắn:

Việc {2,}tìm kiếm regex cho ký tự đứng trước nó và tìm chuỗi con trong khoảng từ 2 đến không giới hạn.
Việc .Replace(temp, " ")thay thế tất cả các kết quả trong temp chuỗi bằng một khoảng trắng.

Nếu bạn muốn sử dụng nhiều lần, đây là một tùy chọn tốt hơn, vì nó tạo ra regex IL tại thời gian biên dịch:

Regex singleSpacify = new Regex(" {2,}", RegexOptions.Compiled);
temp = singleSpacify.Replace(temp, " ");

7

không Regex, không Linq ... xóa các khoảng trắng ở đầu và cuối cũng như giảm bất kỳ phân đoạn không gian nhúng nào vào một không gian

string myString = "   0 1 2  3   4               5  ";
myString = string.Join(" ", myString.Split(new char[] { ' ' }, 
StringSplitOptions.RemoveEmptyEntries));

kết quả: "0 1 2 3 4 5"


1
Một lời cảnh báo: Việc sử dụng chia, trong khi rất đơn giản để hiểu thực sự, có thể có tác động tiêu cực đáng ngạc nhiên. Vì có thể tạo nhiều chuỗi, bạn sẽ phải xem mức sử dụng bộ nhớ của mình trong trường hợp bạn xử lý các chuỗi lớn bằng phương pháp này.
Pac0

5

Giải thích các câu trả lời khác, theo Joel, và hy vọng sẽ cải thiện đôi chút khi tôi đi:

Bạn có thể làm điều này với Regex.Replace():

string s = Regex.Replace (
    "   1  2    4 5", 
    @"[ ]{2,}", 
    " "
    );

Hoặc với String.Split():

static class StringExtensions
{
    public static string Join(this IList<string> value, string separator)
    {
        return string.Join(separator, value.ToArray());
    }
}

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");

3

Tôi vừa viết một bài mới Joinmà tôi thích, vì vậy tôi nghĩ tôi sẽ trả lời lại, với nó:

public static string Join<T>(this IEnumerable<T> source, string separator)
{
    return string.Join(separator, source.Select(e => e.ToString()).ToArray());
}

Một trong những điều thú vị về điều này là nó hoạt động với các bộ sưu tập không phải là chuỗi, bằng cách gọi ToString () trên các phần tử. Cách sử dụng vẫn như cũ:

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");

2
Tại sao tạo một phương thức mở rộng? Tại sao không chỉ sử dụng chuỗi.Join ()?
Eric Schoonover

3
      // Mysample string
            string str ="hi you           are          a demo";

            //Split the words based on white sapce
            var demo= str .Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));

            //Join the values back and add a single space in between
                    str = string.Join(" ", demo);

//output: string str ="hi you are a demo";

2

Tôi biết điều này khá cũ, nhưng đã chạy qua điều này trong khi cố gắng hoàn thành điều tương tự. Tìm thấy giải pháp này trong RegEx Buddy. Mẫu này sẽ thay thế tất cả các không gian đôi bằng các không gian đơn và cũng cắt bớt các không gian hàng đầu và dấu.

pattern: (?m:^ +| +$|( ){2,})
replacement: $1

Hơi khó đọc một chút vì chúng ta đang xử lý không gian trống, do đó, một lần nữa với "khoảng trắng" được thay thế bằng "_".

pattern: (?m:^_+|_+$|(_){2,})  <-- don't use this, just for illustration.

Cấu trúc "(? M:" cho phép tùy chọn "nhiều dòng". Tôi thường muốn bao gồm bất kỳ tùy chọn nào tôi có thể trong chính mẫu để nó khép kín hơn.


2

Nhiều câu trả lời đang cung cấp đầu ra phù hợp nhưng với những người tìm kiếm màn trình diễn tốt nhất, tôi đã cải thiện câu trả lời của Nolanar (đó là câu trả lời tốt nhất cho hiệu suất) khoảng 10%.

public static string MergeSpaces(this string str)
{

    if (str == null)
    {
        return null;
    }
    else
    {
        StringBuilder stringBuilder = new StringBuilder(str.Length);

        int i = 0;
        foreach (char c in str)
        {
            if (c != ' ' || i == 0 || str[i - 1] != ' ')
                stringBuilder.Append(c);
            i++;
        }
        return stringBuilder.ToString();
    }

}

1

Tôi có thể loại bỏ khoảng trắng với điều này

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.

có nhưng bạn sẽ chỉ thay thế hai khoảng trắng bằng một. Điều này sẽ không giúp X số lượng không gian
MGot90

1
Vòng lặp While đó sẽ xử lý tất cả các khoảng trắng kép cần loại bỏ.
Học viên1947

1

Sử dụng mẫu biểu thức chính

    [ ]+    #only space

   var text = Regex.Replace(inputString, @"[ ]+", " ");

1

thử phương pháp này

private string removeNestedWhitespaces(char[] st)
{
    StringBuilder sb = new StringBuilder();
    int indx = 0, length = st.Length;
    while (indx < length)
    {
        sb.Append(st[indx]);
        indx++;
        while (indx < length && st[indx] == ' ')
            indx++;
        if(sb.Length > 1  && sb[0] != ' ')
            sb.Append(' ');
    }
    return sb.ToString();
}

sử dụng nó như thế này:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());

Điều này sẽ xóa các dấu cách
The_Black_Smurf

Xin lỗi vì lỗi này, tôi đã sửa mã, bây giờ nó hoạt động như chuỗi thử nghiệm dự kiến: chuỗi kết quả "1 2 3 4 9": "1 2 3 4 9"
Ahmed Aljaff

1

Đây là một sửa đổi nhỏ về câu trả lời ban đầu của Nolonar .

Kiểm tra xem ký tự không chỉ là khoảng trắng, mà là bất kỳ khoảng trắng nào, hãy sử dụng:

Nó sẽ thay thế bất kỳ ký tự khoảng trắng nào bằng một khoảng trắng.

public static string FilterWhiteSpaces(string input)
{
    if (input == null)
        return string.Empty;

    var stringBuilder = new StringBuilder(input.Length);
    for (int i = 0; i < input.Length; i++)
    {
        char c = input[i];
        if (i == 0 || !char.IsWhiteSpace(c) || (char.IsWhiteSpace(c) && 
            !char.IsWhiteSpace(strValue[i - 1])))
            stringBuilder.Append(c);
    }
    return stringBuilder.ToString();
}

0

Skool cũ:

string oldText = "   1 2  3   4    5     ";
string newText = oldText
                    .Replace("  ", " " + (char)22 )
                    .Replace( (char)22 + " ", "" )
                    .Replace( (char)22 + "", "" );

Assert.That( newText, Is.EqualTo( " 1 2 3 4 5 " ) );

0

Không sử dụng biểu thức chính quy:

while (myString.IndexOf("  ", StringComparison.CurrentCulture) != -1)
{
    myString = myString.Replace("  ", " ");
}

OK để sử dụng trên các chuỗi ngắn, nhưng sẽ hoạt động kém trên các chuỗi dài có nhiều khoảng trống.


0

Kết hợp StringBuilderEnumerable.Aggregate () làm phương thức mở rộng cho chuỗi:

using System;
using System.Linq;
using System.Text;

public static class StringExtension
{
    public static string StripSpaces(this string s)
    {
        return s.Aggregate(new StringBuilder(), (acc, c) =>
        {
            if (c != ' ' || acc.Length > 0 && acc[acc.Length-1] != ' ')
                acc.Append(c);

            return acc;
        }).ToString();
    }

    public static void Main()
    {
        Console.WriteLine("\"" + StringExtension.StripSpaces("1   Hello       World  2   ") + "\"");
    }
}

Đầu vào:

"1   Hello       World  2   "

Đầu ra:

"1 Hello World 2 "
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.