Xóa khoảng trắng khỏi std :: string trong C ++


222

Cách ưa thích để loại bỏ khoảng trắng khỏi chuỗi trong C ++ là gì? Tôi có thể lặp qua tất cả các ký tự và xây dựng một chuỗi mới, nhưng có cách nào tốt hơn không?

Câu trả lời:


257

Điều tốt nhất để làm là sử dụng thuật toán remove_ifvà isspace:

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

Bây giờ, thuật toán tự nó không thể thay đổi vùng chứa (chỉ sửa đổi các giá trị), vì vậy nó thực sự xáo trộn các giá trị xung quanh và trả về một con trỏ đến nơi kết thúc bây giờ. Vì vậy, chúng ta phải gọi chuỗi :: erase để thực sự sửa đổi độ dài của container:

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

Chúng ta cũng nên lưu ý rằng remove_if sẽ tạo tối đa một bản sao của dữ liệu. Đây là một triển khai mẫu:

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
Vì 'isspace' có tình trạng quá tải, nên có lẽ bạn sẽ cần phải đủ điều kiện sử dụng mã chung để sử dụng :: isspace (việc triển khai C không lấy ngôn ngữ) hoặc được chào đón với các lỗi khởi tạo mẫu mã hóa.
Bklyn

4
Tất cả - hãy cảnh giác với phương pháp trên (Hai dòng đơn, không phải phiên bản templated, mặc dù nó có thể có cùng một vấn đề). Tôi đã sử dụng nó trong một dự án mà không nhận ra rằng nó không phải lúc nào cũng đúng. Ví dụ: nếu bạn truyền cho nó chuỗi "1 + 1" thì nó trả về "1 + 11". Tôi đã chuyển sang phương pháp của @rupello bên dưới và nó hoạt động tốt trong trường hợp này. Chúc mừng mã hóa!
JoeB

6
@Joe Câu trả lời rõ ràng đề cập rằng bạn cần gọi erasesau đó. Điều đó sẽ trả về kết quả chính xác.
Konrad Rudolph

31
-1 việc sử dụng isspacenày là UB cho tất cả các bộ ký tự ngoại trừ ASCII 7 bit gốc. C99 §7.4 / 1. điều đó không làm tôi ngạc nhiên khi nó đã được nâng lên thành giai điệu với 71 phiếu bầu, mặc dù là Lời khuyên rất tệ.
Chúc mừng và hth. - Alf

16
Chỉ cần lặp lại, mã trong câu trả lời này chuyển các giá trị âm (khác với EOF) cho isspace, đối với tất cả các ký tự không phải ASCII, với lựa chọn mặc định trong thực tế là ký kết cho char. Do đó, nó có hành vi không xác định . Tôi đang lặp lại nó bởi vì tôi nghi ngờ một nỗ lực cố ý để nhấn chìm sự thật đó trong tiếng ồn.
Chúc mừng và hth. - Alf

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

31
Tôi bỏ phiếu cho việc xóa / xóa thành ngữ chính tắc. Có thể được tạo thành một lớp lót: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Lưu ý: Bạn cần bao gồm <algorithm>để làm việc này.
Tara

37

Từ gamedev

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

22
Điều này sẽ không biên dịch trên các triển khai tuân thủ tiêu chuẩn do quá tải lấy địa phương của std :: isspace. Bạn sẽ cần sử dụng :: isspace hoặc thực hiện một số âm mưu không thể đọc được với std :: bind2nd. Mã chung không đẹp sao?
Bklyn

Cũng lưu ý rằng nếu bất kỳ ký tự nào là âm (ví dụ: char UTF8 khi char được ký), thì sử dụng ::isspacelà UB.
Martin Bonner hỗ trợ Monica

30

Bạn có thể sử dụng Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/opes_algo/usage.html#id1290573

erase_all(str, " "); 

3
Nó chậm hơn so với remove_if(str.begin(), str.end(), isspace);Matt Price đã đề cập. Tôi không biết tại sao. Trên thực tế, tất cả các công cụ tăng cường, có các lựa chọn thay thế STL, đều chậm hơn các công cụ gcc tương ứng (Tất cả những công cụ tôi đã thử nghiệm). Một số trong số họ là rất chậm! (tối đa 5 lần khi chèn unordered_map) Có thể đó là do bộ đệm CPU của môi trường dùng chung hoặc một cái gì đó tương tự.
Etherealone

16

Để cắt tỉa, sử dụng thuật toán chuỗi boost :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"

15

Bạn có thể sử dụng giải pháp này để xóa char:

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

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

1
#include <string.h> bằng cách sử dụng không gian tên std;
slackmart

Giải pháp này là chính xác cho tôi. Cái đầu thì không.
Jason Liu

1
sử dụng không gian tên std nên tránh. stackoverflow.com/questions/1452721/ hy
infinitezero

12

Xin chào, bạn có thể làm một cái gì đó như thế. Hàm này xóa tất cả các khoảng trắng.

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

Tôi đã thực hiện một chức năng khác, đó là xóa tất cả các không gian không cần thiết.

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

sử dụng nó:

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

7

Nếu bạn muốn làm điều này với một macro dễ dàng, đây là một:

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

Điều này giả định bạn đã làm #include <string>tất nhiên.

Gọi nó như vậy:

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

5
Tại sao bạn lại sử dụng macro cho việc này?
dani

1
Bàn phím ít hơn cho một nhiệm vụ chung.
Volomike

3
Tương tự ngắn cho trang web cuộc gọi đang gọi một hàm lấy tham chiếu giá trị đến một chuỗi. Các macro có thể có các hành vi đáng ngạc nhiên khi tương tác với các đối số của chúng (đặc biệt là các tác dụng phụ), nhưng tệ hơn, nếu chúng có lỗi, tên của chúng không hiển thị trong các thông báo của trình biên dịch, việc thực hiện chúng sẽ xảy ra.
Chris Uzdavinis

2

Tôi đã sử dụng các công việc dưới đây xung quanh lâu - không chắc về sự phức tạp của nó.

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

khi bạn muốn loại bỏ ký tự ' 'và một số ví dụ - sử dụng

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

tương tự, chỉ cần tăng ||số lượng ký tự bạn muốn xóa không phải là 1

nhưng như đã đề cập bởi những người khác, xóa thành ngữ cũng có vẻ tốt.


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

    return newWord;
}

Mã này về cơ bản lấy một chuỗi và lặp qua mọi ký tự trong nó. Sau đó, nó kiểm tra xem chuỗi đó có phải là khoảng trắng hay không, nếu không thì ký tự đó sẽ được thêm vào chuỗi mới.


1
   #include <algorithm>
   using namespace std;

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

Nguồn:

Tham khảo lấy từ diễn đàn này .


1
Điều này không thực sự thêm bất cứ điều gì nhiều hơn câu trả lời này đã làm. Có nhiều lời giải thích hoặc chi tiết bạn có thể thêm vào để làm cho câu trả lời của bạn có chất lượng cao hơn và đáng để giữ câu hỏi này không?
Das_Geek

Tôi nghĩ nó đơn giản hơn , vì nó làm điều tương tự trong một tuyên bố.
Giăng

2
Tuyệt quá! Sau đó đặt lý do đó như một lời giải thích trực tiếp trong câu trả lời của bạn . Câu hỏi ban đầu đã hơn mười một tuổi và không có lời biện minh nào, câu trả lời của bạn có thể bị coi là nhiễu khi so sánh với các câu trả lời được chấp nhận, được đánh giá cao khác. Có lời giải thích đó sẽ giúp giữ cho câu trả lời của bạn không bị xóa.
Das_Geek

Điều đó sẽ tốt nhưng tôi không thể hiểu được rằng làm thế nào tôi nên đưa vào câu trả lời của mình ... rằng câu trả lời của tôi tốt hơn câu trả lời này . ? Sẽ là một niềm vui lớn nếu bạn có thể chỉnh sửa câu trả lời của tôi.
Giăng

2
Thật không may, việc tự chỉnh sửa câu trả lời của bạn để thêm nội dung đó sẽ đi ngược lại các nguyên tắc chỉnh sửa và chỉnh sửa của tôi có thể bị từ chối hoặc quay lại sau. Bạn có thể sử dụng liên kết đầu tiên trong bình luận này để tự chỉnh sửa câu trả lời. Hoàn toàn chấp nhận được khi bạn nghĩ rằng câu trả lời của bạn tốt hơn câu trả lời khác và cung cấp lời biện minh cho câu hỏi đó. Cộng đồng sẽ quyết định xem bạn có đúng hay không bằng cách nâng cấp hoặc hạ cấp.
Das_Geek

0

Trong C ++ 20, bạn có thể sử dụng chức năng miễn phí std :: erase

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

Ví dụ đầy đủ:

#include<string>
#include<iostream>

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

Tôi in | do đó, rõ ràng là không gian lúc bắt đầu cũng bị loại bỏ.

lưu ý: điều này chỉ xóa khoảng trắng, không phải mọi ký tự có thể khác có thể được coi là khoảng trắng, xem https://en.cppreference.com/w/cpp/opes/byte/isspace


0

Xóa tất cả các ký tự khoảng trắng như tab và ngắt dòng (C ++ 11):

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

Tại sao bạn muốn đề xuất phương pháp này qua câu trả lời được chấp nhận của @ Matt-Price từ hơn một thập kỷ trước?
Jeremy Caney

Hãy để tất cả các giải pháp được trình bày ở đây. Có lẽ ai đó sẽ cần giải pháp này.
AnselmRu

Tôi không tranh cãi về điều đó. Tôi đang nói giúp mọi người dễ dàng đánh giá các cách tiếp cận khác nhau bằng cách giải thích sự khác biệt và kịch bản nào họ có thể phù hợp hơn.
Jeremy Caney

1
Có lẽ giải pháp này không phải là kinh tế nhất, nhưng nó cho phép bạn loại bỏ tất cả các ký tự khoảng trắng '\ s', không chỉ là khoảng trắng ''.
AnselmRu

0
  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

đầu ra: 2CF4323CB9DE


-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
Nói chung, bạn nên thêm một lời giải thích ngắn gọn cho câu trả lời mã.
arcyqwerty 04/05/2015

1
@test - length()trả về a size_t, không phải an int. erase()mất một size_type, không phải một int. Hàm có thể sẽ thất bại nếu gặp hai khoảng trắng liên tiếp do chỉ số luôn tăng. Nếu một khoảng trắng bị xóa, thì vòng lặp sẽ đọc vượt ra ngoài giới hạn của chuỗi. Bạn có lẽ nên xóa câu trả lời này vì nó cần rất nhiều sự giúp đỡ.
jww

-3

Tôi sợ đó là giải pháp tốt nhất mà tôi có thể nghĩ ra. Nhưng bạn có thể sử dụng dự trữ () để phân bổ trước bộ nhớ tối thiểu cần thiết trước để tăng tốc mọi thứ một chút. Bạn sẽ kết thúc với một chuỗi mới có thể sẽ ngắn hơn nhưng chiếm cùng một lượng bộ nhớ, nhưng bạn sẽ tránh được việc phân bổ lại.

EDIT: Tùy thuộc vào tình huống của bạn, điều này có thể phát sinh ít chi phí hơn so với các nhân vật lộn xộn xung quanh.

Bạn nên thử các cách tiếp cận khác nhau và xem điều gì là tốt nhất cho bạn: bạn có thể không có bất kỳ vấn đề nào về hiệu suất.


remove_if tạo tối đa một bản sao của mỗi giá trị. Vì vậy, thực sự không có quá nhiều chi phí liên quan đến những gì cần phải làm.
Matt Giá
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.