ลบช่องว่างออกจาก std :: string ใน C ++


222

วิธีที่แนะนำในการลบช่องว่างออกจากสตริงใน C ++ คืออะไร ฉันสามารถวนรอบตัวละครทั้งหมดและสร้างสายอักขระใหม่ แต่มีวิธีที่ดีกว่า

คำตอบ:


257

สิ่งที่ดีที่สุดที่ต้องทำคือใช้อัลกอริทึมremove_ifและ isspace:

remove_if(str.begin(), str.end(), isspace);

ตอนนี้อัลกอริทึมตัวเองไม่สามารถเปลี่ยนคอนเทนเนอร์ (ปรับเปลี่ยนค่าเท่านั้น) ดังนั้นมันจึงสลับค่ารอบ ๆ และส่งกลับตัวชี้ไปยังจุดสิ้นสุดที่ควรจะเป็นตอนนี้ ดังนั้นเราต้องเรียกสตริง :: ลบเพื่อแก้ไขความยาวของคอนเทนเนอร์จริง:

str.erase(remove_if(str.begin(), str.end(), isspace), str.end());

นอกจากนี้เราควรทราบว่า remove_if จะทำสำเนาข้อมูลอย่างน้อยหนึ่งชุด นี่คือตัวอย่างการใช้งาน:

template<typename T, typename P>
T remove_if(T beg, T end, P pred)
{
    T dest = beg;
    for (T itr = beg;itr != end; ++itr)
        if (!pred(*itr))
            *(dest++) = *itr;
    return dest;
}

54
เนื่องจาก 'isspace' มีการโหลดมากเกินไปคุณอาจจะต้องมีคุณสมบัติรหัสทั่วไปที่จะใช้ :: isspace (การติดตั้ง C ที่ไม่ใช้ภาษา) หรือได้รับการต้อนรับด้วยข้อผิดพลาดการเริ่มต้นแม่แบบ cryptic
Bklyn

4
ทั้งหมด - ระวังวิธีการข้างต้น (ทั้งสองบรรทัดไม่ใช่เวอร์ชันเทมเพลตแม้ว่าอาจมีปัญหาเดียวกัน) ฉันใช้มันในโครงการโดยไม่ทราบว่ามันไม่ถูกต้องเสมอไป ตัวอย่างเช่นถ้าคุณผ่านมันสตริง "1 + 1" มันจะส่งกลับ "1 + 11" ฉันเปลี่ยนเป็นวิธีการของ @rupello ด้านล่างและทำงานได้ดีสำหรับกรณีนี้ การเข้ารหัสมีความสุข!
JoeB

6
@Joe คำตอบระบุอย่างชัดเจนว่าคุณต้องโทรหาeraseหลังจากนั้น ที่จะส่งคืนผลลัพธ์ที่ถูกต้อง
Konrad Rudolph

31
-1 การใช้นี้isspaceคือ UB สำหรับชุดอักขระทั้งหมดยกเว้น ASCII 7 บิตดั้งเดิม C99 §7.4 / 1 มันไม่แปลกใจฉันว่าจะได้รับการปรับแต่ง upvoted 71 คะแนนเสียงโดยขณะนี้แม้จะแนะนำที่ดีมาก
ไชโยและ hth - Alf

16
เพียงเพื่อทำซ้ำรหัสในคำตอบนี้ผ่านค่าลบ (แตกต่างจาก EOF) ไปisspaceสำหรับทุกอักขระที่ไม่ใช่ ASCII กับตัวเลือกเริ่มต้นในการปฏิบัติของ signedness charสำหรับ ดังนั้นมันจึงมีพฤติกรรมที่ไม่ได้กำหนด ฉันทำซ้ำเพราะฉันสงสัยว่ามีความพยายามในการกลบเสียงดังกล่าวโดยเจตนา
ไชโยและ hth - Alf

100
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());

31
คะแนนโหวตสูงสุดของฉันสำหรับการลบ / การลบแบบบัญญัติ สามารถทำให้เป็นหนึ่งซับ: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
หมายเหตุ: คุณต้องรวม<algorithm>การทำงานนี้ไว้ด้วย
ธารา

37

จากgamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());

22
สิ่งนี้จะไม่คอมไพล์ในการนำไปใช้งานที่เป็นไปตามมาตรฐานเนื่องจากโอเวอร์โหลดที่ใช้โลแคลของ std :: isspace คุณจะต้องใช้ :: isspace หรือดำเนินการ machinations ที่ไม่สามารถอ่านได้ด้วย std :: bind2nd รหัสทั่วไปไม่สวยใช่ไหม
Bklyn

นอกจากนี้โปรดทราบว่าหากตัวละครใด ๆ เป็นลบ (เช่น UTF8 ตัวอักษรเมื่อถ่านลงนาม) การใช้::isspaceเป็น UB
Martin Bonner สนับสนุน Monica

30

คุณสามารถใช้ Boost String Algo ได้ไหม? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 

3
ช้ากว่าremove_if(str.begin(), str.end(), isspace);ราคาที่แมตต์กล่าวไว้ ฉันไม่รู้ว่าทำไม ที่จริงแล้วทุกสิ่งที่เพิ่มที่มีทางเลือก STL ช้ากว่า gcc ที่เกี่ยวข้อง (ทุกสิ่งที่ฉันทดสอบ) บางส่วนของพวกเขาช้าลงอย่างมาก! (มากถึง 5 ครั้งในส่วนแทรก unordered_map) อาจเป็นเพราะแคช CPU ของสภาพแวดล้อมที่ใช้ร่วมกันหรือบางสิ่งบางอย่างเช่นนั้น
Etherealone


15

คุณสามารถใช้วิธีนี้ในการลบถ่าน:

#include <algorithm>
#include <string>
using namespace std;

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());

1
#include <string.h> ใช้ namespace std;
slackmart

วิธีนี้ถูกต้องสำหรับฉัน อันแรกไม่ได้
Jason Liu

1
ควรหลีกเลี่ยงการใช้ namespace std stackoverflow.com/questions/1452721/…
infinitezero

12

สวัสดีคุณสามารถทำอะไรแบบนั้นได้ ฟังก์ชั่นนี้จะลบช่องว่างทั้งหมด

string delSpaces(string &str) 
{
   str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
   return str;
}

ฉันสร้างอีกฟังก์ชั่นหนึ่งซึ่งจะลบพื้นที่ที่ไม่จำเป็นทั้งหมดออก

string delUnnecessary(string &str)
{
    int size = str.length();
    for(int j = 0; j<=size; j++)
    {
        for(int i = 0; i <=j; i++)
        {
            if(str[i] == ' ' && str[i+1] == ' ')
            {
                str.erase(str.begin() + i);
            }
            else if(str[0]== ' ')
            {
                str.erase(str.begin());
            }
            else if(str[i] == '\0' && str[i-1]== ' ')
            {
                str.erase(str.end() - 1);
            }
        }
    }
    return str;
}

8
string replaceinString(std::string str, std::string tofind, std::string toreplace)
{
        size_t position = 0;
        for ( position = str.find(tofind); position != std::string::npos; position = str.find(tofind,position) )
        {
                str.replace(position ,1, toreplace);
        }
        return(str);
}

ใช้มัน:

string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");

7

หากคุณต้องการทำสิ่งนี้ด้วยแมโครที่ง่ายนี่คืออัน:

#define REMOVE_SPACES(x) x.erase(std::remove(x.begin(), x.end(), ' '), x.end())

สิ่งนี้ถือว่าคุณได้ทำ#include <string>แน่นอน

เรียกว่าเป็นเช่นนั้น:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>

5
ทำไมคุณถึงใช้มาโครสำหรับสิ่งนี้
dani

1
แป้นพิมพ์ที่พิมพ์น้อยลงสำหรับงานทั่วไป
Volomike

3
สั้นพอ ๆ กันสำหรับไซต์การโทรกำลังเรียกใช้ฟังก์ชันที่มีการอ้างอิง lvalue กับสตริง มาโครสามารถมีพฤติกรรมที่น่าประหลาดใจในการโต้ตอบกับข้อโต้แย้งของพวกเขา (โดยเฉพาะกับผลข้างเคียง) แต่ที่แย่กว่านั้นคือหากพวกเขามีส่วนร่วมในข้อผิดพลาดชื่อของพวกเขาจะไม่ปรากฏในข้อความคอมไพเลอร์
Chris Uzdavinis

2

ฉันใช้การทำงานด้านล่างเป็นเวลานาน - ไม่แน่ใจเกี่ยวกับความซับซ้อนของมัน

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return (f==' '||s==' ');}),s.end());

เมื่อคุณต้องการที่จะลบตัวอักษร' 'และบางอย่างสำหรับการ- ใช้งานตัวอย่าง

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return ((f==' '||s==' ')||(f=='-'||s=='-'));}),s.end());

ในทำนองเดียวกันก็เพิ่ม||จำนวนตัวละครที่คุณต้องการลบไม่ใช่ 1

แต่ตามที่ผู้อื่นกล่าวถึงการลบการถอดสำนวนยังดูดี


1
string removeSpaces(string word) {
    string newWord;
    for (int i = 0; i < word.length(); i++) {
        if (word[i] != ' ') {
            newWord += word[i];
        }
    }

    return newWord;
}

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


1
   #include <algorithm>
   using namespace std;

   int main() {
       .
       .
       s.erase( remove( s.begin(), s.end(), ' ' ), s.end() );
       .
       .
   }

ที่มา:

การอ้างอิงที่นำมาจากนี้ฟอรั่ม


1
นี่ไม่ได้เพิ่มอะไรมากไปกว่าคำตอบนี้แล้ว มีคำอธิบายหรือรายละเอียดเพิ่มเติมที่คุณสามารถเพิ่มเพื่อทำให้คำตอบของคุณมีคุณภาพสูงขึ้นและคุ้มค่ากับการรักษาคำถามนี้หรือไม่?
Das_Geek

ฉันคิดว่ามันง่ายกว่า 'เพราะมันทำสิ่งเดียวกันในข้อความเดียว
จอห์น

2
ที่ดี! แล้วใส่ให้เหตุผลว่าเป็นคำอธิบายโดยตรงในคำตอบของคุณ คำถามดั้งเดิมมีอายุมากกว่าสิบเอ็ดปีและหากไม่มีเหตุผลที่เหมาะสมคำตอบของคุณอาจถูกมองว่าเป็นเสียงเมื่อเปรียบเทียบกับคำตอบอื่น ๆ ที่เป็นที่ยอมรับและมีชื่อเสียง การมีคำอธิบายนั้นจะช่วยป้องกันไม่ให้คำตอบของคุณถูกลบออกไป
Das_Geek

นั่นจะเป็นสิ่งที่ดีแต่ฉันไม่สามารถได้รับที่วิธีการที่ฉันควรใส่ที่ลงในคำตอบของฉัน ... ว่าคำตอบของฉันดีกว่าคำตอบนี้ ? มันจะเป็นความยินดีอย่างยิ่งหากคุณสามารถแก้ไขคำตอบของฉัน
จอห์น

2
น่าเสียดายที่การแก้ไขคำตอบของคุณเพื่อเพิ่มเนื้อหานั้นจะขัดกับแนวทางการแก้ไขและการแก้ไขของฉันน่าจะถูกปฏิเสธหรือย้อนกลับในภายหลัง คุณสามารถใช้ลิงค์แรกในความคิดเห็นนี้เพื่อแก้ไขคำตอบด้วยตัวเอง เป็นที่ยอมรับโดยสิ้นเชิงว่าคุณคิดว่าคำตอบของคุณดีกว่าคำตอบอื่นและให้เหตุผลสำหรับคำตอบนั้น ชุมชนจะตัดสินใจว่าคุณถูกต้องโดยเลื่อนขึ้นหรือลง
Das_Geek

0

ใน C ++ 20 คุณสามารถใช้ฟังก์ชันฟรี std :: erase

std::string str = " Hello World  !";
std::erase(str, ' ');

ตัวอย่างเต็มรูปแบบ:

#include<string>
#include<iostream>

int main() {
    std::string str = " Hello World  !";
    std::erase(str, ' ');
    std::cout << "|" << str <<"|";
}

ฉันพิมพ์ | เพื่อให้เห็นได้ชัดว่าพื้นที่ที่จุดเริ่มต้นถูกลบออกด้วย

หมายเหตุ: การดำเนินการนี้จะลบเฉพาะที่ว่างไม่ใช่อักขระที่เป็นไปได้อื่น ๆ ที่อาจถูกพิจารณาว่าเป็นช่องว่างให้ดูhttps://en.cppreference.com/w/cpp/string/byte/isspace


0

ลบอักขระช่องว่างทั้งหมดเช่นแท็บและตัวแบ่งบรรทัด (C ++ 11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");

ทำไมคุณถึงแนะนำวิธีการนี้เหนือคำตอบที่ได้รับการยอมรับของ @ Matt-Price จากเมื่อสิบปีก่อน?
Jeremy Caney

ให้การแก้ปัญหาทั้งหมดแสดงที่นี่ อาจมีบางคนต้องการโซลูชันนี้
AnselmRu

ฉันไม่ได้โต้แย้งกับสิ่งนั้น ฉันกำลังพูดว่าทำให้ผู้คนประเมินวิธีการต่าง ๆ ได้ง่ายขึ้นโดยอธิบายความแตกต่างและสถานการณ์ที่พวกเขาอาจจะเหมาะสมกว่า
Jeremy Caney

1
อาจเป็นวิธีนี้ไม่ใช่วิธีประหยัดที่สุด แต่ช่วยให้คุณกำจัดอักขระช่องว่างทั้งหมด '\ s' ไม่ใช่แค่เว้นวรรค ''
AnselmRu


-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}

3
เป็นที่ต้องการโดยทั่วไปว่าคุณเพิ่มคำอธิบายสั้น ๆ เพื่อตอบรหัส
arcyqwerty

1
@test - length()ผลตอบแทนที่ไม่size_t ใช้เวลาไม่ใช่ ฟังก์ชั่นอาจล้มเหลวหากพบช่องว่างต่อเนื่องสองรายการเนื่องจากดัชนีนั้นเพิ่มขึ้นเสมอ หากหนึ่งช่องว่างถูกลบออกจากนั้นวงจะอ่านเกินขอบเขตของสตริง คุณควรลบคำตอบนี้เพราะต้องการความช่วยเหลือมากมาย interase()size_typeint
jww

-3

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

แก้ไข: ขึ้นอยู่กับสถานการณ์ของคุณนี้อาจมีค่าใช้จ่ายน้อยกว่าตัวอักษร jumbling รอบ ๆ

คุณควรลองแนวทางที่แตกต่างและดูว่าอะไรดีที่สุดสำหรับคุณ: คุณอาจไม่มีปัญหาด้านประสิทธิภาพเลย


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