Bir dizeden baştaki ve sondaki boşlukları kaldırma


92

C ++ 'da bir dize nesnesindeki boşluklar nasıl kaldırılır.
Örneğin, aşağıdaki dize nesnesinden baştaki ve sondaki boşlukların nasıl kaldırılacağı.

//Original string: "         This is a sample string                    "
//Desired string: "This is a sample string"

String sınıfı, bildiğim kadarıyla baştaki ve sondaki boşlukları kaldırmak için herhangi bir yöntem sağlamıyor.

Soruna ek olarak, dizedeki sözcükler arasındaki fazladan boşlukları işlemek için bu biçimlendirmenin nasıl genişletileceği. Örneğin,

// Original string: "          This       is         a sample   string    " 
// Desired string:  "This is a sample string"  

Çözümde bahsedilen string yöntemlerini kullanarak bu işlemleri iki adımda yapmayı düşünebilirim.

  1. Baştaki ve sondaki boşlukları kaldırın.
  2. Kullanım find_first_of, find_last_of, find_first_not_of, find_last_not_of ve substr , defalarca kelimeye sınırları biçimlendirme istenen almak.

Yanıtlar:


128

Buna kırpma denir. Boost'u kullanabiliyorsanız , tavsiye ederim.

Aksi takdirde, find_first_not_ofilk boşluk olmayan karakterin find_last_not_ofdizinini almak , ardından dizini boşluk olmayan sondan almak için kullanın. Bunlarla substr, alt dizeyi çevreleyen beyaz boşluk olmadan elde etmek için kullanın .

Düzenlemenize yanıt olarak, terimi bilmiyorum, ancak "azaltma" çizgisinde bir şey olduğunu tahmin ediyorum, bu yüzden onu adlandırdım. :) (Unutmayın, esneklik için beyaz boşluğu bir parametre olarak değiştirdim)

#include <iostream>
#include <string>

std::string trim(const std::string& str,
                 const std::string& whitespace = " \t")
{
    const auto strBegin = str.find_first_not_of(whitespace);
    if (strBegin == std::string::npos)
        return ""; // no content

    const auto strEnd = str.find_last_not_of(whitespace);
    const auto strRange = strEnd - strBegin + 1;

    return str.substr(strBegin, strRange);
}

std::string reduce(const std::string& str,
                   const std::string& fill = " ",
                   const std::string& whitespace = " \t")
{
    // trim first
    auto result = trim(str, whitespace);

    // replace sub ranges
    auto beginSpace = result.find_first_of(whitespace);
    while (beginSpace != std::string::npos)
    {
        const auto endSpace = result.find_first_not_of(whitespace, beginSpace);
        const auto range = endSpace - beginSpace;

        result.replace(beginSpace, range, fill);

        const auto newStart = beginSpace + fill.length();
        beginSpace = result.find_first_of(whitespace, newStart);
    }

    return result;
}

int main(void)
{
    const std::string foo = "    too much\t   \tspace\t\t\t  ";
    const std::string bar = "one\ntwo";

    std::cout << "[" << trim(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo) << "]" << std::endl;
    std::cout << "[" << reduce(foo, "-") << "]" << std::endl;

    std::cout << "[" << trim(bar) << "]" << std::endl;
}

Sonuç:

[too much               space]  
[too much space]  
[too-much-space]  
[one  
two]  

'size_t' demek istediğinizi varsayıyorum. ve alt dizede tek tek var, substr olmalı (beginStr, endStr - beginStr + 1);
goldPseudo

Meli site_tolmak size_t? Ve bence yorumun olduğu yerde no whitespacedizenin tamamen boşluk veya boş olduğu anlamına geliyor.
Fred Larson

Teşekkürler size_t yazım hatası düzenlemede tek tek , ancak yorumumun ters çevrildiğini fark etmedim, teşekkürler.
GManNickG

@GMan çok zarif bir çözüm. Teşekkürler.
Ankur

Hata: trim () aracılığıyla "bir \ ttwo" çalıştırmayı deneyin. Sonuç boş bir dizedir. Ayrıca endStr'yi std :: string :: npos'a karşı test etmeniz gerekir.
dlchambers

48

Bir satırdaki std :: string'den baştaki, sondaki ve ekstra boşlukları kolayca kaldırma

value = std::regex_replace(value, std::regex("^ +| +$|( ) +"), "$1");

sadece baştaki boşlukları kaldırmak

value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));

veya

value = std::regex_replace(value, std::regex("^ +"), "");

sadece sondaki boşlukları kaldırmak

value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());

veya

value = std::regex_replace(value, std::regex(" +$"), "");

sadece fazladan boşlukları kaldırmak

value = regex_replace(value, std::regex(" +"), " ");

3
Güzel. Bu kodları anlamak zor olduğundan, burada neler olduğu hakkında biraz bilgi vermek faydalı olacaktır.
Marcin

Yine de yalnızca C ++ 11'de çalışır.
Martin Pecka

7
Sekmeleri kaldırmaz, ancak bu düzeltilebilir. Düzeltilemeyen şey, çok yavaş olmasıdır ( substrveya ile verilen yanıtlardan ~ 100 kat daha yavaş erase).
4LegsDrivenCat

hız optimizasyonu için normal ifade en uygun çözüm değildir, ancak bir kez bir normal ifade örneği oluşturarak iyileştirilebilir
Evgeny Karpov

40

Şu anda bu işlevleri kullanıyorum:

// trim from left
inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

// trim from right
inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v")
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

// trim from left & right
inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v")
{
    return ltrim(rtrim(s, t), t);
}

// copying versions

inline std::string ltrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return ltrim(s, t);
}

inline std::string rtrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return rtrim(s, t);
}

inline std::string trim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
    return trim(s, t);
}


9

Baştaki ve sondaki boşlukları çıkarmak için benim çözümüm bu ...

std::string stripString = "  Plamen     ";
while(!stripString.empty() && std::isspace(*stripString.begin()))
    stripString.erase(stripString.begin());

while(!stripString.empty() && std::isspace(*stripString.rbegin()))
    stripString.erase(stripString.length()-1);

Sonuç "Plamen" dir


8

İşte bunu nasıl yapabileceğiniz:

std::string & trim(std::string & str)
{
   return ltrim(rtrim(str));
}

Ve destekleyici işlevler şu şekilde uygulanır:

std::string & ltrim(std::string & str)
{
  auto it2 =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( str.begin() , it2);
  return str;   
}

std::string & rtrim(std::string & str)
{
  auto it1 =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( it1.base() , str.end() );
  return str;   
}

Ve tüm bunları bir kez yerine getirdikten sonra, bunu da yazabilirsiniz:

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

Bunu dene


7

Jon-hanson'un artırma kullanma önerisini takiben baştaki ve sondaki boşlukları kırpma örneği (yalnızca sondaki ve bekleyen boşlukları kaldırır):

#include <boost/algorithm/string/trim.hpp>

std::string str = "   t e s t    ";

boost::algorithm::trim ( str );

Sonuçlar "t e s t"

Ayrıca birde şu var

  • trim_left sonuçlanır "t e s t "
  • trim_right sonuçlanır " t e s t"

5
/// strip a string, remove leading and trailing spaces
void strip(const string& in, string& out)
{
    string::const_iterator b = in.begin(), e = in.end();

    // skipping leading spaces
    while (isSpace(*b)){
        ++b;
    }

    if (b != e){
        // skipping trailing spaces
        while (isSpace(*(e-1))){
            --e;
        }
    }

    out.assign(b, e);
}

Yukarıdaki kodda, isSpace () işlevi, bir karakterin beyaz boşluk olup olmadığını söyleyen bir boole işlevidir, bu işlevi ihtiyaçlarınızı yansıtacak şekilde uygulayabilir veya isterseniz "ctype.h" den isspace () 'i çağırabilirsiniz. .


4

Baştaki ve sondaki boşlukları kırpma örneği

std::string aString("    This is a string to be trimmed   ");
auto start = aString.find_first_not_of(' ');
auto end = aString.find_last_not_of(' ');
std::string trimmedString;
trimmedString = aString.substr(start, (end - start) + 1);

VEYA

trimmedSring = aString.substr(aString.find_first_not_of(' '), (aString.find_last_not_of(' ') - aString.find_first_not_of(' ')) + 1);

3
İnsanlar, bir dizeyi nasıl kırpacaklarını öğrenmek için 10 sayfalık kodlara bakmaktan hoşlanmaz.
Thinkal VB

2
dizede yalnızca boşluk varsa
DAG

3

Standart kitaplığı kullanmanın birçok yararı vardır, ancak istisnalara neden olan bazı özel durumların farkında olunması gerekir. Örneğin, yanıtların hiçbiri bir C ++ dizesinin bazı Unicode karakterlerinin olduğu durumu kapsamaz. Bu durumda, isspace işlevini kullanırsanız , bir istisna atılır.

Dizeleri kırpmak ve kullanışlı olabilecek diğer bazı işlemler için aşağıdaki kodu kullanıyorum. Bu kodun başlıca faydaları: gerçekten hızlıdır (şimdiye kadar test ettiğim herhangi bir koddan daha hızlıdır), yalnızca standart kitaplığı kullanır ve hiçbir zaman bir istisnaya neden olmaz:

#include <string>
#include <algorithm>
#include <functional>
#include <locale>
#include <iostream>

typedef unsigned char BYTE;

std::string strTrim(std::string s, char option = 0)
{
    // convert all whitespace characters to a standard space
    std::replace_if(s.begin(), s.end(), (std::function<int(BYTE)>)::isspace, ' ');

    // remove leading and trailing spaces
    size_t f = s.find_first_not_of(' ');
    if (f == std::string::npos) return "";
    s = s.substr(f, s.find_last_not_of(' ') - f + 1);

    // remove consecutive spaces
    s = std::string(s.begin(), std::unique(s.begin(), s.end(),
        [](BYTE l, BYTE r){ return l == ' ' && r == ' '; }));

    switch (option)
    {
    case 'l':  // convert to lowercase
        std::transform(s.begin(), s.end(), s.begin(), ::tolower);
        return s;
    case 'U':  // convert to uppercase
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    case 'n':  // remove all spaces
        s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
        return s;
    default: // just trim
        return s;
    }
}

3

Bu en basit olanı olabilir.

Sen kullanabilirsiniz string::findve string::rfindher iki taraftan da boşluklar bulmaya ve dize azaltır.

void TrimWord(std::string& word)
{
    if (word.empty()) return;

    // Trim spaces from left side
    while (word.find(" ") == 0)
    {
        word.erase(0, 1);
    }

    // Trim spaces from right side
    size_t len = word.size();
    while (word.rfind(" ") == --len)
    {
        word.erase(len, len + 1);
    }
}

2

Bunu test ettim, hepsi çalışıyor. Yani bu yöntem processInput, kullanıcıdan sadece bir şeyler yazmasını isteyecektir. Başında veya sonunda fazladan boşluk veya boşluk içermeyen bir dize döndürecektir. Bu yardımcı olur umarım. (ayrıca anlaşılmasını kolaylaştırmak için bir yığın yorum ekleyin).

nasıl uygulayacağınızı alttaki main () bölümünde görebilirsiniz.

#include <string>
#include <iostream>

string processInput() {
  char inputChar[256];
  string output = "";
  int outputLength = 0;
  bool space = false;
  // user inputs a string.. well a char array
  cin.getline(inputChar,256);
  output = inputChar;
       string outputToLower = "";
  // put characters to lower and reduce spaces
  for(int i = 0; i < output.length(); i++){
    // if it's caps put it to lowercase
    output[i] = tolower(output[i]);
    // make sure we do not include tabs or line returns or weird symbol for null entry array thingy
    if (output[i] != '\t' && output[i] != '\n' && output[i] != 'Ì') {
      if (space) {
        // if the previous space was a space but this one is not, then space now is false and add char
        if (output[i] != ' ') {
          space = false;
          // add the char
          outputToLower+=output[i];
        }
      } else {
        // if space is false, make it true if the char is a space
        if (output[i] == ' ') {
          space = true;
        }
        // add the char
        outputToLower+=output[i];
      }
    }
  }
  // trim leading and tailing space
  string trimmedOutput = "";
  for(int i = 0; i < outputToLower.length(); i++){
    // if it's the last character and it's not a space, then add it
    // if it's the first character and it's not a space, then add it
    // if it's not the first or the last then add it
    if (i == outputToLower.length() - 1 && outputToLower[i] != ' ' || 
      i == 0 && outputToLower[i] != ' ' || 
      i > 0 && i < outputToLower.length() - 1) {
      trimmedOutput += outputToLower[i];
    } 
  }
  // return
  output = trimmedOutput;
  return output;
}

int main() {
  cout << "Username: ";
  string userName = processInput();
  cout << "\nModified Input = " << userName << endl;
}

2

Neden karmaşıklaştın?

std::string removeSpaces(std::string x){
    if(x[0] == ' ') { x.erase(0, 1); return removeSpaces(x); }
    if(x[x.length() - 1] == ' ') { x.erase(x.length() - 1, x.length()); return removeSpaces(x); }
    else return x;
}

Bu, yükseltme başarısız olsa bile, normal ifade yok, tuhaf şeyler veya kitaplıklar olmasa bile çalışır.

DÜZENLEME: MM'nin yorumu için düzeltme.


Bu, boşluk uzunluğunu hesaplamaya ve her uç için tek bir silme çağrısı kullanmaya kıyasla biraz verimsizdir
MM

1

C ++ 17 tanıtıldı std::basic_string_view, karakter benzeri nesnelerin sabit bir bitişik sırasına, yani dizenin bir görünümüne başvuran bir sınıf şablonu. İle çok benzer bir arayüze sahip olmasının yanı sıra std::basic_string, iki ek işlevi vardır: remove_prefix()başlangıcını ileri doğru hareket ettirerek görünümü küçülten; ve remove_suffix()ucunu geriye doğru hareket ettirerek görünümü küçültür. Bunlar baştaki ve sondaki boşluğu kırpmak için kullanılabilir:

#include <string_view>
#include <string>

std::string_view ltrim(std::string_view str)
{
    const auto pos(str.find_first_not_of(" \t"));
    str.remove_prefix(pos);
    return str;
}

std::string_view rtrim(std::string_view str)
{
    const auto pos(str.find_last_not_of(" \t"));
    str.remove_suffix(str.length() - pos - 1);
    return str;
}

std::string_view trim(std::string_view str)
{
    str = ltrim(str);
    str = rtrim(str);
    return str;
}

int main()
{
    std::string str = "   hello world   ";
    auto sv1{ ltrim(str) };  // "hello world   "
    auto sv2{ rtrim(str) };  // "   hello world"
    auto sv3{ trim(str) };   // "hello world"

    //If you want, you can create std::string objects from std::string_view objects
    auto s1{ sv1 };
    auto s2{ sv2 };
    auto s3{ sv3 };
}

Not: the std::string_view, sahip olunmayan bir referanstır, bu nedenle yalnızca orijinal dize hala var olduğu sürece geçerlidir.


0
    char *str = (char*) malloc(50 * sizeof(char));
    strcpy(str, "    some random string (<50 chars)  ");

    while(*str == ' ' || *str == '\t' || *str == '\n')
            str++;

    int len = strlen(str);

    while(len >= 0 && 
            (str[len - 1] == ' ' || str[len - 1] == '\t' || *str == '\n')
    {
            *(str + len - 1) = '\0';
            len--;
    }

    printf(":%s:\n", str);

0
void removeSpaces(string& str)
{
    /* remove multiple spaces */
    int k=0;
    for (int j=0; j<str.size(); ++j)
    {
            if ( (str[j] != ' ') || (str[j] == ' ' && str[j+1] != ' ' ))
            {
                    str [k] = str [j];
                    ++k;
            }

    }
    str.resize(k);

    /* remove space at the end */   
    if (str [k-1] == ' ')
            str.erase(str.end()-1);
    /* remove space at the begin */
    if (str [0] == ' ')
            str.erase(str.begin());
}

0
string trim(const string & sStr)
{
    int nSize = sStr.size();
    int nSPos = 0, nEPos = 1, i;
    for(i = 0; i< nSize; ++i) {
        if( !isspace( sStr[i] ) ) {
            nSPos = i ;
            break;
        }
    }
    for(i = nSize -1 ; i >= 0 ; --i) {
        if( !isspace( sStr[i] ) ) {
            nEPos = i;
            break;
        }
    }
    return string(sStr, nSPos, nEPos - nSPos + 1);
}

0

Baştaki ve sondaki boşluklar için:

string string_trim(const string& in) {

    stringstream ss;
    string out;
    ss << in;
    ss >> out;
    return out;

}

Veya bir cümle için:

string trim_words(const string& sentence) {
    stringstream ss;
    ss << sentence;
    string s;
    string out;

    while(ss >> s) {

        out+=(s+' ');
    }
    return out.substr(0, out.length()-1);
}

0

düzgün ve temiz

 void trimLeftTrailingSpaces(string &input) {
        input.erase(input.begin(), find_if(input.begin(), input.end(), [](int ch) {
            return !isspace(ch);
        }));
    }

    void trimRightTrailingSpaces(string &input) {
        input.erase(find_if(input.rbegin(), input.rend(), [](int ch) {
            return !isspace(ch);
        }).base(), input.end());
    }

0

Hayır boost, hayır regex, sadece stringkütüphane. Bu kadar basit.

string trim(const string s) { // removes whitespace characters from beginnig and end of string s
    const int l = (int)s.length();
    int a=0, b=l-1;
    char c;
    while(a<l && ((c=s.at(a))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) a++;
    while(b>a && ((c=s.at(b))==' '||c=='\t'||c=='\n'||c=='\v'||c=='\f'||c=='\r'||c=='\0')) b--;
    return s.substr(a, 1+b-a);
}

1
... ve yapınıza 2 milyon başlık dosyası eklemekten kaçındınız!
Larry_C

0

Soruna ek olarak, dizedeki sözcükler arasındaki fazladan boşlukları işlemek için bu biçimlendirmenin nasıl genişletileceği.

Aslında bu, birden çok baştaki ve sondaki beyaz boşluk karakterlerini hesaba katmaktan daha basit bir durumdur. Yapmanız gereken tek şey, bitişik beyaz boşluk karakterlerini tüm dizeden kaldırmaktır.

Bitişik beyaz boşluğun yüklemi basitçe şöyle olacaktır:

auto by_space = [](unsigned char a, unsigned char b) {
    return std::isspace(a) and std::isspace(b);
};

ve sonra bu yinelenen bitişik boşluk karakterlerinden std::uniqueve sil-kaldır deyiminden kurtulabilirsiniz :

// s = "       This       is       a sample   string     "  
s.erase(std::unique(std::begin(s), std::end(s), by_space), 
        std::end(s));
// s = " This is a sample string "  

Bu, potansiyel olarak önde ve / veya arkada fazladan bir boşluk karakteri bırakır. Bu oldukça kolay bir şekilde kaldırılabilir:

if (std::size(s) && std::isspace(s.back()))
    s.pop_back();

if (std::size(s) && std::isspace(s.front()))
    s.erase(0, 1);

İşte bir demo .


-1

Bu sorun için Çözümüm herhangi bir STL yöntemi kullanmıyor, ancak yalnızca C ++ dizesinin kendi yöntemleri aşağıdaki gibidir

void processString(string &s) {
    if ( s.empty() ) return;

    //delete leading and trailing spaces of the input string
    int notSpaceStartPos = 0, notSpaceEndPos = s.length() - 1;
    while ( s[notSpaceStartPos] == ' ' ) ++notSpaceStartPos;
    while ( s[notSpaceEndPos] == ' ' ) --notSpaceEndPos;
    if ( notSpaceStartPos > notSpaceEndPos ) { s = ""; return; }
    s = s.substr(notSpaceStartPos, notSpaceEndPos - notSpaceStartPos + 1);

    //reduce multiple spaces between two words to a single space 
    string temp;
    for ( int i = 0; i < s.length(); i++ ) {
        if ( i > 0 && s[i] == ' ' && s[i-1] == ' ' ) continue;
        temp.push_back(s[i]);
    }
    s = temp;
}

Bu yöntemi bir LeetCode problemini geçmek için kullandım Bir Dizedeki Kelimeleri Ters Çevir


-1
void TrimWhitespaces(std::wstring& str)
{
    if (str.empty())
        return;

    const std::wstring& whitespace = L" \t";
    std::wstring::size_type strBegin = str.find_first_not_of(whitespace);
    std::wstring::size_type strEnd = str.find_last_not_of(whitespace);

    if (strBegin != std::wstring::npos || strEnd != std::wstring::npos)
    {
        strBegin == std::wstring::npos ? 0 : strBegin;
        strEnd == std::wstring::npos ? str.size() : 0;

        const auto strRange = strEnd - strBegin + 1;
        str.substr(strBegin, strRange).swap(str);
    }
    else if (str[0] == ' ' || str[0] == '\t')   // handles non-empty spaces-only or tabs-only
    {
        str = L"";
    }
}

void TrimWhitespacesTest()
{
    std::wstring EmptyStr = L"";
    std::wstring SpacesOnlyStr = L"    ";
    std::wstring TabsOnlyStr = L"           ";
    std::wstring RightSpacesStr = L"12345     ";
    std::wstring LeftSpacesStr = L"     12345";
    std::wstring NoSpacesStr = L"12345";

    TrimWhitespaces(EmptyStr);
    TrimWhitespaces(SpacesOnlyStr);
    TrimWhitespaces(TabsOnlyStr);
    TrimWhitespaces(RightSpacesStr);
    TrimWhitespaces(LeftSpacesStr);
    TrimWhitespaces(NoSpacesStr);

    assert(EmptyStr == L"");
    assert(SpacesOnlyStr == L"");
    assert(TabsOnlyStr == L"");
    assert(RightSpacesStr == L"12345");
    assert(LeftSpacesStr == L"12345");
    assert(NoSpacesStr == L"12345");
}

-2

Ne hakkında silme-remove deyim ?

std::string s("...");
s.erase( std::remove(s.begin(), s.end(), ' '), s.end() );

Afedersiniz. Tüm boşlukları kaldırmak istemediğini çok geç gördüm .


Merhaba, artık cevabın yanlış olduğunun farkına vardığına göre, istersen silebilirsin. Bu şekilde, bu cevapta DV'lerden kaybettiğiniz temsilciyi geri alacaksınız :)
repliği geri alacaksınız
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.