ฉันจะแทนที่ช่องว่างหลายช่องด้วยช่องว่างเดียวใน C # ได้อย่างไร


440

ฉันจะแทนที่ช่องว่างหลายรายการในสตริงด้วยช่องว่างเดียวใน C # ได้อย่างไร

ตัวอย่าง:

1 2 3  4    5

อยากจะเป็น:

1 2 3 4 5

1
เครื่องรัฐสามารถทำได้อย่างง่ายดาย แต่ก็อาจเกินกำลังหากคุณต้องการเพียงเพื่อลบช่องว่าง
Adrian

ฉันได้เพิ่มมาตรฐานเกี่ยวกับวิธีการที่แตกต่างกันในการทำเช่นนี้ในคำถามที่ซ้ำกันstackoverflow.com/a/37592018/582061 Regex ไม่ใช่วิธีที่เร็วที่สุดในการทำเช่นนี้
Stian Standahl

คำตอบ:


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
ฉันมีการคัดลอกและวางและใช้งานได้ ฉันไม่ชอบ REgex จริงๆ แต่คราวนี้มันช่วยชีวิตฉันไว้
Pokus

9
@Craig ความคิดเห็นจะเพียงพอ IMO // บล็อกนี้แทนที่ช่องว่างหลายช่องด้วยหนึ่งช่อง ... :)
paulwhit

6
จริง ๆ แล้ว RegEx มีราคาแพงเกินไปสำหรับสิ่งนี้
Joel Coehoorn

11
@Joel: ไม่เห็นด้วย ฉันแน่ใจว่าจริง ๆ แล้ววิธีนี้มีประสิทธิภาพมากกว่าของคุณสำหรับสตริงมากพอและสามารถทำได้ในบรรทัดเดียว overkill อยู่ที่ไหน
Konrad Rudolph

24
รหัสของ @Oscar Joel นั้นไม่ได้วนซ้ำไปมาง่ายๆเลย! มันเป็นลูปซ้อนกันที่ซ่อนเร้น ในทางตรงกันข้ามการแสดงออกปกติเป็นแบบเชิงเส้นจะสร้างสตริงเดียวเท่านั้น (= ลดค่าใช้จ่ายในการจัดสรรอย่างมากเมื่อเทียบกับรหัสของ Joel) และเครื่องยนต์ยังสามารถเพิ่มประสิทธิภาพให้กับนรกได้ (จริงๆแล้วฉันสงสัยว่า regex .NET คือ ฉลาดพอสำหรับเรื่องนี้ แต่ในทางทฤษฎีแล้วนิพจน์ทั่วไปนี้สามารถนำไปใช้งานได้ในราคาถูกจนไม่ตลกอีกต่อไปมันต้องการเพียง DFA ที่มีสามสถานะหนึ่งการเปลี่ยนแปลงแต่ละอันและไม่มีข้อมูลเพิ่มเติม)
Konrad Rudolph

624

ฉันชอบที่จะใช้:

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

เนื่องจากมันจะจับช่องว่างใด ๆ (เช่นแท็บบรรทัดใหม่ ฯลฯ ) และแทนที่ด้วยช่องว่างเดียว


43
การปรับเปลี่ยนเล็กน้อย: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); นี่จะส่งคืนประเภทช่องว่างแรกที่พบ ดังนั้นถ้าคุณมี 5 แท็บมันจะกลับแท็บ เผื่อคนที่ชอบสิ่งนี้
FB สิบ Kate

@radistao ลิงก์ของคุณสำหรับสตริง Javascript แทนที่ไม่ใช่สำหรับ C #
พระอิศวร

1
@Shiva, / \ s \ s + / เป็นคำสั่ง POSIX regex มาตรฐานและอาจถูกแปลง / ใช้ในภาษาใด ๆ ที่ใช้ไวยากรณ์ของตัวเอง
radistao

4
ด้วยจิตวิญญาณของโซลูชั่นของ @ FBtenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); จะแทนที่อักขระที่อยู่ติดกันหลายชุดด้วยอักขระตัวเดียว
François Beaune

1
เพื่อที่จะลบช่องว่างนำหน้าและต่อท้ายคุณควรใช้ฟังก์ชัน Trim () ด้วยเช่น, เช่น 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
นี่สามารถอ่านได้มากกว่า regex ฉันชอบมากกว่าเพราะฉันไม่ต้องการเรียนรู้ไวยากรณ์อื่น ๆ
Michael Bahig

9
ฉันชอบเพราะไม่จำเป็นต้องใช้ Regex
AleX_

3
นี่จะไม่มีประสิทธิภาพสำหรับสตริงขนาดใหญ่
DarcyThomas

3
นอกจากนี้ยังลบช่องว่างนำหน้าและต่อท้าย
Matzi

1
ฉันชอบคำตอบนี้เช่นกัน ที่ปรึกษาเก่าของฉันเคยพูดว่า "เมื่อใดก็ตามที่คุณมีปัญหาที่คุณคิดว่าคุณต้องใช้ Regex ในการแก้ปัญหา ... ตอนนี้คุณมีปัญหาสองอย่าง" <วิ้งก์>
วิลเลียมมาดอนน่าจูเนียร์

38

ฉันคิดว่าคำตอบของ Matt ดีที่สุด แต่ฉันไม่เชื่อว่ามันค่อนข้างถูก หากคุณต้องการแทนที่บรรทัดใหม่คุณต้องใช้:

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

4
RegexOptions.Multiline เปลี่ยนความหมายของ ^ และ $ เพื่อให้ตรงกับจุดเริ่มต้นและจุดสิ้นสุดของทุกบรรทัด ($ = \ n) แทนที่จะเป็นสตริงหลายบรรทัดทั้งหมด เนื่องจาก \ s เทียบเท่ากับ [\ f \ n \ r \ t \ v] บรรทัดใหม่ควรถูกแทนที่แม้ว่าตัวเลือก Multiline จะปิดอยู่
SushiGuy

1
คำตอบของแมตต์ครอบคลุมไปถึงเรื่องนี้แล้ว ฉัน 'เชื่อ' 30 คนเพิ่งปิดตาโหวตให้คำตอบนี้ :)
123iamking

26

อีกวิธีหนึ่งซึ่งใช้ LINQ:

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

23

มันง่ายกว่านั้นมาก:

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

23
สิ่งนี้จะมีประสิทธิภาพน้อยกว่า regex "{2,}" ถ้าสตริงมีลำดับของช่องว่าง 3 หรือมากกว่า
Jan Goyvaerts

2
@JanGoyvaerts: แม้จะมี 10 ช่องว่าง regex ก็ช้าลงเมื่อฉันทำการทดสอบที่รวดเร็วและสกปรก ที่ถูกกล่าวว่าจะใช้เวลาเพียงหนึ่ง substring ยักษ์เต็มไปด้วยช่องว่างเพื่อฆ่าประสิทธิภาพของห่วงในขณะที่ เพื่อความเป็นธรรมฉันใช้ฉันใช้ RegexOptions.Compiled แทนที่จะใช้ Regex.Replace ที่ช้ากว่า
Brian

5
RegexOptions.Compiled เพิ่มค่าใช้จ่ายในการรวบรวม regex ให้เป็นจำนวนมาก อย่าใช้มันเว้นแต่ว่าแอปพลิเคชันของคุณจะใช้ regex บ่อยครั้งเพียงพอหรือบนสตริงที่มีขนาดใหญ่พอที่ความเร็วการจับคู่ที่เพิ่มขึ้นจะชดเชยความเร็วในการรวบรวมที่ลดลง
Jan Goyvaerts

นี่คือตัวอย่างของรหัสที่ไม่มีประสิทธิภาพมาก ฮ่า ๆ.
pcbabu

1
@pcbabu มันไม่ได้เลวร้ายอย่างที่เห็นในหลาย ๆ กรณี Replace()วิธีการจะจัดการกับเหตุการณ์ที่เกิดขึ้นทั้งหมดของสองช่องว่างในสตริงที่กำหนดดังนั้นเราจะไม่วนลูป (และอีกจัดสรรสตริงทั้ง) สำหรับอินสแตนซ์ของพื้นที่จับคู่ทุกคนในสตริง การจัดสรรใหม่หนึ่งรายการจะจัดการทั้งหมดได้ เราเรียกใช้การวนซ้ำอีกครั้งเมื่อมีช่องว่าง 3 ช่องขึ้นไปด้วยกันซึ่งน่าจะเกิดขึ้นได้ยากยิ่งขึ้นสำหรับแหล่งสัญญาณเข้าจำนวนมาก หากคุณสามารถแสดงว่ามันเป็นปัญหาสำหรับข้อมูลของคุณให้ไปเขียนเครื่องสถานะเพื่อผลักดันตัวละครโดยตัวละครในตัวสร้างสตริงใหม่
Joel Coehoorn

21

Regex ค่อนข้างช้าแม้จะมีงานง่ายๆ 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();
        }
    }

มันจะถูกใช้เป็นเช่นนี้:

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


11

สำหรับผู้ที่ไม่ชอบRegexนี่คือวิธีการที่ใช้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();
    }

ในการทดสอบของฉันวิธีนี้เร็วขึ้น 16 เท่าโดยเฉลี่ยด้วยชุดสตริงขนาดเล็กถึงขนาดกลางที่มีขนาดใหญ่มากเทียบกับ Regex ที่รวบรวมแบบคงที่ เมื่อเทียบกับ Regex ที่ไม่ได้รวบรวมหรือไม่คงที่นี่ควรจะเร็วยิ่งขึ้น

โปรดทราบว่ามันไม่ได้ลบช่องว่างนำหน้าหรือตามหลัง แต่มีเหตุการณ์เกิดขึ้นหลายครั้งเท่านั้น


หากคุณต้องการตรวจสอบว่าตัวละครตัวนี้เป็นช่องว่างและไม่เพียง แต่พื้นที่ ดูคำตอบของฉันด้านล่าง
เก็บเกี่ยว

8

คุณสามารถทำได้ในโซลูชันเดียว!

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

คุณสามารถเลือกวงเล็บอื่น ๆ (หรือตัวละครอื่น ๆ ) หากคุณต้องการ


1
คุณต้องตรวจสอบให้แน่ใจว่าสตริงของคุณไม่มี "()" หรือ ") (" ในนั้นหรือ"wel()come to london)("กลายเป็น"wel come to london"คุณสามารถลองใช้วงเล็บจำนวนมากดังนั้นใช้((((()))))แทน()และ)))))(((((แทน)(มันจะยังคงทำงานถ้า สตริงมี((((()))))หรือ)))))(((((สิ่งนี้จะล้มเหลว
nmit026

7

นี่เป็นเวอร์ชั่นที่สั้นกว่าซึ่งควรใช้เฉพาะเมื่อคุณทำสิ่งนี้เพียงครั้งเดียวเท่านั้นเพราะมันจะสร้างอินสแตนซ์ใหม่ของRegexคลาสทุกครั้งที่มีการเรียกใช้

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

หากคุณไม่คุ้นเคยกับการแสดงออกปกตินี่เป็นคำอธิบายสั้น ๆ :

{2,}ทำให้การค้นหา regex สำหรับตัวละครก่อนหน้านั้นและพบว่าสตริงระหว่าง 2 และไม่ จำกัด จำนวนครั้ง แทนที่การแข่งขันทั้งหมดในอุณหภูมิสตริงด้วยช่องว่าง
.Replace(temp, " ")

หากคุณต้องการใช้หลาย ๆ ครั้งนี่เป็นตัวเลือกที่ดีกว่าเพราะสร้าง regex IL ในเวลารวบรวม:

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

7

ไม่มี Regex, ไม่มี Linq ... ลบช่องว่างนำหน้าและต่อท้ายรวมทั้งลดพื้นที่ว่างหลาย ๆ ส่วนที่ฝังลงในหนึ่งช่องว่าง

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

ผลลัพธ์: "0 1 2 3 4 5"


1
คำเตือน: การใช้การแบ่งขณะที่ง่ายมากที่จะเข้าใจแน่นอนสามารถส่งผลกระทบเชิงลบอย่างน่าประหลาดใจ เนื่องจากสามารถสร้างสตริงจำนวนมากได้คุณจะต้องดูการใช้หน่วยความจำของคุณในกรณีที่คุณจัดการกับสตริงขนาดใหญ่ด้วยวิธีนี้
Pac0

5

การหาคำตอบอื่น ๆ ต่อโจเอลและหวังว่าจะดีขึ้นเล็กน้อยเมื่อฉันไป:

คุณสามารถทำได้ด้วยRegex.Replace():

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

หรือด้วย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

ฉันเพิ่งเขียนใหม่Joinที่ฉันชอบดังนั้นฉันคิดว่าฉันตอบอีกครั้งด้วย:

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

หนึ่งในสิ่งที่ยอดเยี่ยมเกี่ยวกับเรื่องนี้คือมันทำงานกับคอลเลกชันที่ไม่ได้เป็นสตริงโดยการเรียก ToString () บนองค์ประกอบ การใช้งานยังคงเหมือนเดิม:

//...

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

2
เหตุใดจึงสร้างวิธีส่วนขยาย ทำไมไม่ใช้แค่ string.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

ฉันรู้ว่ามันค่อนข้างเก่า แต่ก็วิ่งข้ามสิ่งนี้ไปในขณะที่พยายามทำสิ่งเดียวกันให้สำเร็จ พบโซลูชันนี้ใน RegEx Buddy รูปแบบนี้จะแทนที่ช่องว่างคู่ทั้งหมดด้วยช่องว่างเดียวและยังตัดแต่งช่องว่างนำหน้าและต่อท้าย

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

มันยากที่จะอ่านเล็กน้อยเนื่องจากเรากำลังจัดการกับพื้นที่ว่างดังนั้นที่นี่จึงเป็น "ช่องว่าง" แทนที่ด้วย "_" อีกครั้ง

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

โครงสร้าง "(? m:" เปิดใช้งานตัวเลือก "หลายบรรทัด" โดยทั่วไปฉันต้องการรวมตัวเลือกใด ๆ ที่ฉันสามารถทำได้ในรูปแบบของตัวเองเพื่อให้มีอยู่ในตัวเองมากขึ้น


2

มีคำตอบมากมายที่ให้ผลลัพธ์ที่ถูกต้อง แต่สำหรับผู้ที่มองหาผลงานที่ดีที่สุดฉันได้ปรับปรุงคำตอบของ Nolanar (ซึ่งเป็นคำตอบที่ดีที่สุดสำหรับการแสดง) ประมาณ 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

ฉันสามารถลบช่องว่างด้วยสิ่งนี้

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

ใช่ แต่คุณจะแทนที่ช่องว่างสองช่องด้วยอันเดียวเท่านั้น นี่จะไม่ช่วยช่องว่าง X จำนวน
MGot90

1
ในขณะที่ห่วงจะดูแลช่องว่างสองเท่าที่จะถูกลบออก
Learner1947


1

ลองใช้วิธีนี้

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

ใช้มันแบบนี้:

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

สิ่งนี้จะลบช่องว่างต่อท้าย
The_Black_Smurf

ขอโทษสำหรับความผิดพลาดฉันแก้ไขโค้ดตอนนี้มันทำงานได้ตามที่คาดไว้สตริงทดสอบ: "1 2 3 4 9" สตริงผลลัพธ์: "1 2 3 4 9"
Ahmed Aljaff

1

นี่คือการปรับเปลี่ยนเล็กน้อยในNolonar คำตอบเดิม

ตรวจสอบว่าตัวละครไม่ได้เป็นเพียงช่องว่าง แต่เป็นช่องว่างใด ๆ ใช้สิ่งนี้:

มันจะแทนที่อักขระช่องว่างหลาย ๆ อันด้วยช่องว่างเดียว

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 เก่า:

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

โดยไม่ใช้นิพจน์ทั่วไป:

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

ตกลงที่จะใช้กับสตริงสั้น ๆ แต่จะทำงานได้ไม่ดีกับสตริงยาวที่มีช่องว่างมากมาย


0

การผสมผสานของStringBuilderและEnumerable.Aggregate ()เป็นวิธีเสริมสำหรับสตริง:

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   ") + "\"");
    }
}

การป้อนข้อมูล:

"1   Hello       World  2   "

เอาท์พุท:

"1 Hello World 2 "
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.