C ++ 'da std :: string alanlarını kaldırın


222

C ++ 'da bir dizeden boşluk kaldırmanın tercih edilen yolu nedir? Tüm karakterler arasında döngü ve yeni bir dize oluşturmak, ama daha iyi bir yolu var mı?

Yanıtlar:


257

Yapılacak en iyi şey algoritma remove_ifve isspace kullanmaktır :

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

Şimdi algoritmanın kendisi kabı değiştiremez (sadece değerleri değiştirir), bu yüzden aslında değerleri karıştırır ve sonun olması gereken yere bir işaretçi döndürür. Bu nedenle, kabın uzunluğunu gerçekten değiştirmek için string :: erase komutunu çağırmalıyız:

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

Ayrıca remove_if'in verilerin en fazla bir kopyasını oluşturacağını da not etmeliyiz. İşte örnek bir uygulama:

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
'İsspace' aşırı yüklenmeleri nedeniyle, genel kodu :: isspace (bir yerel ayar almayan C uygulaması) veya şifreli şablon örnekleme hatalarıyla karşılaşacak şekilde kullanmanız gerekebilir.
Bklyn

4
Hepsi - yukarıdaki yönteme karşı dikkatli olun (Aynı soruna sahip olabilmesine rağmen, şablonlu sürüm değil, iki tek satır). Her zaman doğru olmadığını fark etmeden bir projede kullandım. Örneğin, "1 + 1" dizesini iletirseniz "1 + 11" değerini döndürür. Aşağıdaki @rupello'nun yöntemine geçtim ve bu durum için iyi çalıştı. Mutlu kodlama!
JoeB

6
@Joe Bu sorunun cevabı açıkça erasesonradan aramanız gerektiğini belirtmektedir . Bu doğru sonucu döndürür.
Konrad Rudolph

31
-1 bu kullanımı isspaceorijinal 7 bit ASCII hariç tüm karakter kümeleri için UB'dir. C99 §7.4 / 1. o sürpriz değil o Çok Kötü Önerileri olmanın rağmen artık 71 oy ayarlamak için upvoted oldu bana.
Şerefe ve s. - Alf

16
Tekrarlamak gerekirse, bu isspaceyanıttaki kod, ASCII olmayan tüm karakterler için uygulamada varsayılan imzalama seçeneğiyle negatif değerleri ( EOF'dan farklı) geçirir char. Böylece tanımlanmamış bir davranışı vardır . Tekrarlıyorum çünkü bu gerçeği gürültüde boğmak için kasıtlı bir girişimden şüpheleniyorum.
Şerefe ve s. - Alf

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

31
Kanonik silme / kaldırma deyimine karşı oylarım. Tek bir astar halinde yapılabilir: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Not: Bunun <algorithm>çalışması için dahil etmeniz gerekir .
Tara

37

Gönderen gamedev

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

22
Bu, std :: isspace parametresinin yerel ayarı aşırı yüklenmeleri nedeniyle standartlara uygun uygulamalarda derlenmez. :: isspace kullanmanız veya std :: bind2nd ile bazı okunamayan işlemeler yapmanız gerekir. Genel kod güzel değil mi?
Bklyn

Ayrıca, karakterlerden herhangi biri negatifse (örneğin, char imzalandığında bir UTF8 karakteri), kullanımının ::isspaceUB olduğunu unutmayın.
Martin Bonner, Monica

30

Boost String Algo kullanabilir misiniz? 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);Matt Price'ın bahsettiğinden daha yavaş . Nedenini bilmiyorum. Aslında, STL alternatifleri olan tüm takviye maddeleri, karşılık gelen gcc olanlardan daha yavaştır (Test ettiğim her şey). Bazıları son derece yavaş! (unordered_map eklerinde 5 kata kadar) Belki de paylaşılan ortamın CPU önbelleği veya bunun gibi bir şey olabilir.
Etherealone

16

Kırpmak için boost dize algoritmaları kullanın :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

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


12

Merhaba, böyle bir şey yapabilirsiniz. Bu işlev tüm boşlukları siler.

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

Gereksiz tüm alanları silen başka bir işlev daha yaptım.

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

kullanın:

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

7

Bunu kolay bir makro ile yapmak istiyorsanız, işte bir tane:

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

Bu #include <string>tabii ki yaptığınızı varsayar .

Öyle söyle:

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

5
bunun için neden makro kullanasın?
dani

1
Ortak bir görev için daha az klavye yazma.
Volomike

3
Çağrı sitesi için eşit derecede kısa bir dizeye lvalue başvurusu alan bir işlevi çağırıyor . Makrolar, argümanlarıyla etkileşime giren şaşırtıcı davranışlara sahip olabilirler (özellikle yan etkilerle), ancak daha da kötüsü, bir hataya karışırlarsa, adları derleyici mesajlarında görünmez, uygulamaları yapar.
Chris Uzdavinis

2

Aşağıdaki çalışmayı uzun süre kullandım - karmaşıklığından emin değilim.

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

Eğer karakteri kaldırın istediğimde ' 'örnek için ve bazı - kullanım

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

aynı şekilde sadece ||kaldırmak istediğiniz karakter sayısı değilse artırmak 1

ancak diğerleri tarafından belirtildiği gibi, silme kaldırma deyimi de iyi görünüyor.


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

    return newWord;
}

Bu kod temelde bir dize alır ve içindeki her karakter boyunca yinelenir. Daha sonra, bu dizenin beyaz boşluk olup olmadığını kontrol eder, eğer değilse, karakter yeni bir dizeye eklenir.


1
   #include <algorithm>
   using namespace std;

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

Kaynak:

Referans bu forumdan alınmıştır .


1
Bu, bu cevabın zaten eklediğinden daha fazla bir şey eklemiyor. Cevabınızı daha yüksek kalite ve bu soruya değer tutmak için ekleyebileceğiniz daha fazla açıklama veya ayrıntı var mı?
Das_Geek

Bence daha basit , çünkü aynı şeyi tek bir ifadede yapıyor.
John

2
Harika! O zaman bu akıl yürütmeyi doğrudan cevabınıza bir açıklama olarak koyun . Orijinal soru on bir yıldan daha eski ve bir gerekçe olmadan, cevabınız kabul edilen, iyi onaylanmış diğer cevaplara kıyasla gürültü olarak görülebilir. Bu açıklamaya sahip olmak, yanıtınızın kaldırılmasını önlemeye yardımcı olacaktır.
Das_Geek

Yani olurdu iyi ama nasıl koymak gerektiğini alamadım o ... cevabım içine cevabım daha iyi olduğunu bu cevabı . ? Cevabımı düzenleyebilmeniz büyük bir mutluluk olurdu .
John

2
Maalesef, bu içeriği kendim eklemek için cevabınızı düzenlemek , düzenleme yönergelerine aykırıdır ve düzenlemem daha sonra reddedilecek veya geri alınacaktır. Cevabı kendiniz düzenlemek için bu yorumdaki ilk bağlantıyı kullanabilirsiniz. Cevabınızın diğerinden daha iyi olduğunu düşündüğünüzü belirtmek ve bunun için gerekçe sunmak tamamen kabul edilebilir. Topluluk, doğru ya da aşağı doğru oy vererek doğru olup olmadığınıza karar verecektir.
Das_Geek

0

C ++ 20'de ücretsiz işlev std :: erase kullanabilirsiniz

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

Tam örnek:

#include<string>
#include<iostream>

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

Yazdırıyorum | böylece başlangıçtaki alanın da kaldırıldığı açıktır.

not: boşluk olarak kabul edilebilecek diğer tüm karakterleri değil, yalnızca alanı kaldırır, bkz. https://en.cppreference.com/w/cpp/string/byte/isspace


0

Sekmeler ve satır sonları (C ++ 11) gibi tüm boşluk karakterlerini kaldırır :

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

Neden bu yaklaşımı on yıldan fazla bir süre önce @ Matt-Price'ın kabul edilen cevabı üzerinde öneriyorsunuz?
Jeremy Caney

Tüm çözümlerin burada sunulmasına izin verin. Belki birisinin bu çözüme ihtiyacı vardır.
AnselmRu

Buna karşı çıkmıyorum. Farklılıkları ve hangi senaryolar için daha uygun olabileceklerini açıklayarak insanların farklı yaklaşımları değerlendirmelerini kolaylaştıracağımı söylüyorum.
Jeremy Caney

1
Muhtemelen bu çözüm en ekonomik değildir, ancak sadece boşluklardan değil , tüm boşluk karakterlerinden '\ s' kurtulmanızı sağlar .
AnselmRu

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

çıktı: 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
Genellikle kod yanıtlarına kısa bir açıklama eklemeniz tercih edilir.
arcyqwerty

1
@test - length()a değerini döndürür size_t, değil int. erase()alır size_type, değil int. Dizin her zaman artırıldığından, art arda iki boşlukla karşılaşılırsa işlev büyük olasılıkla başarısız olur. Bir boşluk kaldırılırsa, döngü dizenin sınırlarının ötesinde okunur. Çok fazla yardıma ihtiyaç duyduğundan muhtemelen bu cevabı silmelisiniz.
jww

-3

Korkarım ki aklıma gelen en iyi çözüm. Ancak, işleri biraz hızlandırmak için gerekli olan minimum belleği önceden ayırmak için Reserve () kullanabilirsiniz. Muhtemelen daha kısa olacak ancak aynı miktarda bellek kaplayan yeni bir dize alacaksınız, ancak yeniden tahsislerden kaçınacaksınız.

DÜZENLEME: Durumunuza bağlı olarak, bu durum etrafta dolaşan karakterlerden daha az ek yüke neden olabilir.

Farklı yaklaşımlar denemeli ve sizin için en iyi olanı görmelisiniz: performans sorunlarınız olmayabilir.


remove_if, her değerin en fazla bir kopyasını oluşturur. Yani yapılması gerekenlerle ilgili o kadar fazla yük yok.
Matt Price
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.