C ++ 'ta bir dizgiyi nasıl belirleyebilirim?


414

Java'nın uygun bir bölünme yöntemi vardır:

String str = "The quick brown fox";
String[] results = str.split(" ");

C ++ bunu yapmanın kolay bir yolu var mı?


172
Bu rutin görevin c ++ 'da böyle bir baş ağrısı olduğuna inanamıyorum
wfbarksdale

6
C ++ 'da baş ağrısı değil - bunu başarmanın çeşitli yolları vardır. programcılar c ++ 'dan c #' dan daha az haberdar - pazarlama ve yatırımlar hakkında ... bunu elde etmek için çeşitli c ++ seçenekleri için bunu görün: cplusplus.com/faq/sequences/strings/split
hB0 31:13

9
@ hB0 birçok soru cevaplar geçiyor ve hala karar vermiyor anlamına gelir bir baş ağrısı. biri kütüphaneye ihtiyaç duyuyor, diğeri sadece mekânlar için, diğeri mekânları
işlemiyor


2
Neden C ++ 'daki her şey bir mücadele olmak zorunda?
Wael Assaf

Yanıtlar:


145

C ++ standart kütüphane algoritmaları, evrensel olarak somut kaplar yerine yineleyiciler etrafında oluşturulmuştur. Ne yazık ki bu split, C ++ standart kütüphanesinde Java benzeri bir işlev sağlamayı zorlaştırıyor , ancak kimse bunun uygun olacağını iddia etmese de. Ancak geri dönüş türü ne olurdu? std::vector<std::basic_string<…>>? Belki, ama sonra (potansiyel olarak gereksiz ve maliyetli) tahsisler yapmaya mecburuz.

Bunun yerine, C ++, dizeleri keyfi olarak karmaşık sınırlayıcılara dayalı olarak bölmenin çok sayıda yolunu sunar, ancak bunların hiçbiri diğer dillerde olduğu gibi güzelce kapsüllenmez. Sayısız yol tüm blog yayınlarını doldurur .

En basit haliyle, siz vuruncaya std::string::findkadar kullanarak yineleme yapabilir std::string::nposve içeriği kullanarak çıkarabilirsiniz std::string::substr.

Boşlukta bölünmek için daha akıcı (ve deyimsel, ancak temel) bir sürüm aşağıdakileri kullanır std::istringstream:

auto iss = std::istringstream{"The quick brown fox"};
auto str = std::string{};

while (iss >> str) {
    process(str);
}

Kullanılması std::istream_iterators , string akışının muhtevası da onun yineleyici aralığı yapıcısı kullanılarak bir vektör içine kopyalanan edilebilir.

Birden fazla kütüphane ( Boost.Tokenizer gibi ) özel belirteçler sunar.

Daha gelişmiş bölme için düzenli ifadeler gerekir. C ++ std::regex_token_iteratorbu amaçla özellikle şunları sağlar:

auto const str = "The quick brown fox"s;
auto const re = std::regex{R"(\s+)"};
auto const vec = std::vector<std::string>(
    std::sregex_token_iterator{begin(str), end(str), re, -1},
    std::sregex_token_iterator{}
);

53
Ne yazık ki, tüm projeler için destek her zaman mevcut değildir. Desteklenmeyen bir cevap aramam gerekecek.
BulanıkBunnySlippers

36
Her proje "açık kaynak" a açık değildir. Ağır düzenlemelere tabi endüstrilerde çalışıyorum. Gerçekten sorun değil. Bu sadece hayatın bir gerçeği. Boost her yerde mevcut değildir.
BulanıkBunnySlippers

5
@NonlinearIdeas Diğer soru / cevap hiç Açık Kaynak projeleri ile ilgili değildi. Aynı durum herhangi bir proje için de geçerlidir . Bununla birlikte, tabii ki MISRA C gibi kısıtlı standartları anlıyorum, ancak her şeyi sıfırdan oluşturduğunuz anlaşılıyor (eğer uyumlu bir kütüphane - nadir bir şey bulamazsanız). Her neyse, mesele şu ki, “Artırma mevcut değil” - neredeyse tüm genel amaçlı cevapların uygun olmayacağı özel gereksinimleriniz var .
Konrad Rudolph

1
@DonlinearIdeas Bu durumda, diğer Boost olmayan yanıtlar da MISRA uyumlu değildir.
Konrad Rudolph

3
@Dmitry “STL barf” nedir ?! Ve tüm topluluk, C önişlemcisinin yerini almayı çok istiyor - aslında, bunu yapmak için öneriler var. Ancak bunun yerine PHP veya başka bir dil kullanma öneriniz geriye doğru büyük bir adım olacaktır.
Konrad Rudolph

188

Boost tokenizer sınıfı oldukça basit bu tür bir şey yapabilir:

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer< char_separator<char> > tokens(text, sep);
    BOOST_FOREACH (const string& t, tokens) {
        cout << t << "." << endl;
    }
}

C ++ 11 için güncellendi:

#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main(int, char**)
{
    string text = "token, test   string";

    char_separator<char> sep(", ");
    tokenizer<char_separator<char>> tokens(text, sep);
    for (const auto& t : tokens) {
        cout << t << "." << endl;
    }
}

1
İyi şeyler, son zamanlarda bunu kullandım. Simgeler (metin, sep) bitinden önce iki ">" karakteri ayırmak için boşluk bırakana kadar Visual Studio derleyicimde garip bir whinge var: (hata C2947: şablon-bağımsız değişken listesini sonlandırmak için '>' bekleniyor 'bulundu'> > ')
AndyUK

@AndyUK evet, boşluk olmadan derleyici iki kapatma şablonu yerine bir çıkarma operatörü olarak ayrıştırır.
EnabrenTane

Teorik olarak bu C ++ 0x ile düzeltildi
David Souther

3
char_separatoryapıcı üçüncü parametrelerine dikkat ( drop_empty_tokensvarsayılan, alternatif keep_empty_tokens).
Benoit

5
@puk - C ++ başlık dosyaları için yaygın olarak kullanılan bir sonektir. ( .hC başlıkları gibi )
Ferruccio

167

İşte gerçekten basit:

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

vector<string> split(const char *str, char c = ' ')
{
    vector<string> result;

    do
    {
        const char *begin = str;

        while(*str != c && *str)
            str++;

        result.push_back(string(begin, str));
    } while (0 != *str++);

    return result;
}

dosyasında bu yöntem için bir prototip eklemem gerekir mi?
Sührob Samiev

5
Bu hala düz C sabit karakter dizisi olan bir dizgi değişmezi kullandığından tam olarak "en iyi" yanıt değildir. Sorgulayan o ikincisi tarafından tanıtıldı türü "dize" olan bir C ++ dize tokenize olabilir soruyordu inanıyordu.
Vijay Kumar Kanta

Bunun yeni bir cevaba ihtiyacı var çünkü C ++ 11'e düzenli ifadelerin dahil edilmesinin en iyi cevabın ne olacağını değiştirdiğinden şüpheleniyorum.
şeye kadir

113

Strtok kullanın. Benim düşünceme göre, strtok size ihtiyacınız olanı sağlamadığı sürece tokenleştirmenin etrafında bir sınıf oluşturmaya gerek yoktur. Bu olmayabilir, ancak C ve C ++ 'da çeşitli ayrıştırma kodu yazmanın 15 yıldan fazla bir süresinde, her zaman strtok kullandım. İşte bir örnek

char myString[] = "The quick brown fox";
char *p = strtok(myString, " ");
while (p) {
    printf ("Token: %s\n", p);
    p = strtok(NULL, " ");
}

Birkaç uyarı (ihtiyaçlarınızı karşılamayabilir). Dize süreçte "yok edilir", yani EOS karakterleri sınırlayıcı noktalara satır içine yerleştirilir. Doğru kullanım, dizenin sabit olmayan bir sürümünü oluşturmanızı gerektirebilir. Ayrıştırma öğelerinin orta ayrıştırma listesini de değiştirebilirsiniz.

Kendi düşünceme göre, yukarıdaki kod bunun için ayrı bir sınıf yazmaktan çok daha basit ve kullanımı daha kolaydır. Bana göre, bu dilin sağladığı işlevlerden biridir ve iyi ve temiz bir şekilde yapar. Bu sadece "C tabanlı" bir çözümdür. Bu uygun, kolay ve çok fazla kod yazmak zorunda değilsiniz :-)


42
C sevmiyorum, ancak strtok iş parçacığı için güvenli değildir ve gönderdiğiniz dize, olası bir arabellek taşmasını önlemek için boş bir karakter içerdiğinden emin olmanız gerekir.
tloach

11
Strtok_r var, ama bu bir C ++ sorusuydu.
Prof. Falken sözleşmesi

3
@tloach: MSS ++ derleyicisinde strtok, iç statik değişken TLS (iş parçacığı yerel depolama) üzerinde oluşturulduğundan iş parçacığı için güvenlidir (aslında derleyiciye bağlıdır)
Ahmed Said

3
@ahmed: thread safe işlevi farklı iş parçacıklarında iki kez çalıştırabilmekten daha fazlası anlamına gelir. Bu durumda, iplik strtok çalışırken değiştirilirse, dizenin tüm strtok çalışması sırasında geçerli olması mümkündür, ancak dizge değiştiği için strtok yine de bozulur, şimdi zaten boş karakteri geçmiştir ve güvenlik ihlali oluşana veya boş karakter bulana kadar belleği okumaya devam edin. Sorunlarla karşılaştığınız bir yerde bir uzunluk belirtmezseniz, bu orijinal C dizesi işlevleriyle ilgili bir sorundur.
tloach

4
strtok, c ++ kodunda bulmak için ortak bir yaratık olmayan const olmayan bir null sonlu char dizisine bir işaretçi gerektirir ... std :: string'den buna dönüştürmek için en sevdiğiniz yol nedir?
fuzzyTew

105

Başka bir hızlı yol kullanmaktır getline. Gibi bir şey:

stringstream ss("bla bla");
string s;

while (getline(ss, s, ' ')) {
 cout << s << endl;
}

İsterseniz, split()a'yı döndürmek için basit bir yöntem yapabilirsiniz vector<string>, bu gerçekten yararlıdır.


2
Bu döngü kullanarak while döngüsü çıkış erken yapılan dize 0x0A karakterlerle sorunları vardı. Aksi takdirde, basit ve hızlı bir çözüm.
Ryan H.

4
Bu iyidir, ancak bunu yaparak varsayılan '\ n' sınırlayıcısının dikkate alınmadığını unutmayın. Bu örnek işe yarayacaktır, ancak şöyle bir şey kullanıyorsanız: (getline (inFile, word, '')) inFile birden fazla satır içeren ifstream nesnesiyse, funnny sonuçları elde edersiniz ..
hackrock

çok kötü GetLink geçici depolama olmadan başlatma listelerindeki kullanılamaz hale, dize yerine akım döndürür var
fuzzyTew

1
Güzel! Destek yok ve C ++ 11, bu eski projelere iyi bir çözüm!
Deqing

1
Bu cevap, fonksiyonun adı sadece biraz garip.
Nils

82

Bunu doğrudan yapmak için akışları, yineleyicileri ve kopyalama algoritmasını kullanabilirsiniz.

#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>

int main()
{
  std::string str = "The quick brown fox";

  // construct a stream from the string
  std::stringstream strstr(str);

  // use stream iterators to copy the stream to the vector as whitespace separated strings
  std::istream_iterator<std::string> it(strstr);
  std::istream_iterator<std::string> end;
  std::vector<std::string> results(it, end);

  // send the vector to stdout.
  std::ostream_iterator<std::string> oit(std::cout);
  std::copy(results.begin(), results.end(), oit);
}

17
Bu std :: okumak için rahatsız edici buluyorum .. neden "kullanma" kullanmıyorsunuz?
user35978

80
@Vadi: Başka birinin gönderisini düzenlemek oldukça müdahaleci. @pheze: Nesnemin stdnereden geldiğini bu şekilde tanımayı tercih ediyorum , bu sadece bir stil meselesi.
Matthieu

7
Sebebini anlıyorum ve bence bu senin için işe yararsa iyi bir seçim, ama pedagojik bir bakış açısıyla aslında pheze ile hemfikirim. Aşağıdaki gibi satırları yorumlamak için daha az çaba gerektirdiğinden, özellikle bu durumda her şey standart kütüphaneden olduğu için, bunun gibi tamamen yabancı bir örneği okumak ve anlamak daha kolaydır. Bir dizi "std :: string;" kullanarak nesnelerin nereden geldiğini okumayı ve açıklamayı kolaylaştırabilirsiniz. Özellikle fonksiyon çok kısa olduğu için.
cheshirekow

61
"Std ::" öneklerinin rahatsız edici veya çirkin olmasına rağmen, bu işlevlerin nereden geldiği tamamen açık olacak şekilde bunları örnek koduna dahil etmek en iyisidir. Sizi rahatsız ediyorsa, örneği çaldıktan ve kendiniz olarak talep ettikten sonra bunları bir "kullanma" ile değiştirmek önemsizdir.
dlchambers

20
Evet! o ne dedi! en iyi uygulamalar std önekini kullanmaktır. Herhangi bir büyük kod tabanı şüphesiz kendi kütüphaneleri ve ad alanları olacak ve "namespace std kullanarak" kullanmak, ad alanı çakışmalarına neden olduğunuzda size baş ağrısı verecektir.
Miek

48

Darılma millet, ama böyle basit bir sorun için, olayları yapıyoruz yolu çok karmaşık. Boost'u kullanmanın birçok nedeni vardır . Ama bu kadar basit bir şey için, 20 # kızak ile bir sinek vurmak gibi.

void
split( vector<string> & theStringVector,  /* Altered/returned value */
       const  string  & theString,
       const  string  & theDelimiter)
{
    UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro.

    size_t  start = 0, end = 0;

    while ( end != string::npos)
    {
        end = theString.find( theDelimiter, start);

        // If at end, use length=maxLength.  Else use length=end-start.
        theStringVector.push_back( theString.substr( start,
                       (end == string::npos) ? string::npos : end - start));

        // If at end, use start=maxSize.  Else use start=end+delimiter.
        start = (   ( end > (string::npos - theDelimiter.size()) )
                  ?  string::npos  :  end + theDelimiter.size());
    }
}

Örneğin (Doug'un davası için),

#define SHOW(I,X)   cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl

int
main()
{
    vector<string> v;

    split( v, "A:PEP:909:Inventory Item", ":" );

    for (unsigned int i = 0;  i < v.size();   i++)
        SHOW( i, v[i] );
}

Ve evet, split () yeni bir vektör döndürmek yerine yeni bir vektör döndürebiliriz. Sarmak ve aşırı yüklemek önemsizdir. Ancak yaptığım şeye bağlı olarak, önceden var olan nesneleri her zaman yenilerini oluşturmak yerine yeniden kullanmayı daha iyi buluyorum. (Vektörü arada boşaltmayı unutmadığım sürece!)

Referans: http://www.cplusplus.com/reference/string/string/ .

(Aslen Doug'un sorusuna bir cevap yazıyordum: C ++ Dizeleri Ayırıcılara Dayalı Değiştirme ve Çıkarma (kapalı) . Ancak Martin York bu soruyu burada bir işaretçi ile kapattığından ... Kodumu genelleştireceğim.)


12
Neden yalnızca bir yerde kullandığınız bir makro tanımlayın. Ve UASSERT'iniz standart iddiasından daha iyi. Karşılaştırmayı bunun gibi 3 jetona bölmek, aksi takdirde ihtiyacınız olandan daha fazla virgül gerektirmez.
crelbor

1
Belki de UASSERT makrosu (hata mesajında) karşılaştırılan iki değer arasındaki gerçek ilişkiyi (ve değerleri) gösterir? Bu aslında oldukça iyi bir fikir, IMHO.
GhassanPL

10
Ugh, std::stringsınıf neden bir split () işlevi içermiyor?
Bay Shickadance

While döngüsünde son satır ve while döngüsünde olması start = ((end > (theString.size() - theDelimiter.size())) ? string::npos : end + theDelimiter.size());gerektiğini düşünüyorum while (start != string::npos). Ayrıca, alt dizeyi vektöre yerleştirmeden önce boş olmadığından emin olmak için kontrol ediyorum.
John K

@JohnK Girdinin arka arkaya iki ayırıcısı varsa, aralarındaki dize açıkça boştur ve vektöre eklenmelidir. Boş değerler belirli bir amaç için kabul edilebilir değilse, bu başka bir şeydir, ancak IMHO bu tür kısıtlamalar bu tür çok genel amaçlı işlevlerin dışında uygulanmalıdır.
Lauri Nurmi

46

S kullanarak bir çözüm regex_token_iterator:

#include <iostream>
#include <regex>
#include <string>

using namespace std;

int main()
{
    string str("The quick brown fox");

    regex reg("\\s+");

    sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
    sregex_token_iterator end;

    vector<string> vec(iter, end);

    for (auto a : vec)
    {
        cout << a << endl;
    }
}

5
Bu en üst sıradaki cevap olmalı. C ++> = 11'de bunu yapmanın doğru yolu budur.
şeye rağmen

1
Bu yanıta kadar aşağı kaydırdım sevindim (şu anda sadece 9 upvotes vardı). Bu, bu görev için tam olarak bir C ++ 11 kodu gibi görünmelidir!
YePhIcK

Dış kütüphanelere dayanmayan ve halihazırda mevcut kütüphaneleri kullanan mükemmel cevap
Andrew

1
Sınırlayıcılarda en fazla esnekliği veren harika yanıt. Birkaç uyarı: \ s + regex kullanımı metnin ortasında boş belirteçleri önler, ancak metin boşlukla başlıyorsa boş bir ilk belirteç verir. Ayrıca, regex yavaş görünüyor: dizüstü bilgisayarımda, 20 MB rastgele metin için, sttok, strsep veya Parham'ın str.find_first_of kullanarak 0.014 sn veya Perl için 0.027 sn veya Python için 0.021 sn ile karşılaştırıldığında, 0.6 saniye sürer. . Kısa metin için hız endişe verici olmayabilir.
Mark Gates

2
Tamam belki havalı görünüyor, ama bu düzenli ifadelerin açıkça aşırı kullanımı. Yalnızca performansı önemsemiyorsanız makul olur.
Marek R

35

Boost'un güçlü bir bölünme işlevi vardır: boost :: algorithm :: split .

Örnek program:

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

int main() {
    auto s = "a,b, c ,,e,f,";
    std::vector<std::string> fields;
    boost::split(fields, s, boost::is_any_of(","));
    for (const auto& field : fields)
        std::cout << "\"" << field << "\"\n";
    return 0;
}

Çıktı:

"a"
"b"
" c "
""
"e"
"f"
""

26

Bir C ++ çözümü istediğini biliyorum, ama bunu yararlı düşünebilirsin:

Qt

#include <QString>

...

QString str = "The quick brown fox"; 
QStringList results = str.split(" "); 

Bu örnekte Boost'a göre avantajı, postanızın koduyla doğrudan bire bir eşleşmesidir.

Qt dokümanlarında daha fazlasını görün


22

İşte istediğini yapabilecek bir örnek belirteç sınıfı

//Header file
class Tokenizer 
{
    public:
        static const std::string DELIMITERS;
        Tokenizer(const std::string& str);
        Tokenizer(const std::string& str, const std::string& delimiters);
        bool NextToken();
        bool NextToken(const std::string& delimiters);
        const std::string GetToken() const;
        void Reset();
    protected:
        size_t m_offset;
        const std::string m_string;
        std::string m_token;
        std::string m_delimiters;
};

//CPP file
const std::string Tokenizer::DELIMITERS(" \t\n\r");

Tokenizer::Tokenizer(const std::string& s) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(DELIMITERS) {}

Tokenizer::Tokenizer(const std::string& s, const std::string& delimiters) :
    m_string(s), 
    m_offset(0), 
    m_delimiters(delimiters) {}

bool Tokenizer::NextToken() 
{
    return NextToken(m_delimiters);
}

bool Tokenizer::NextToken(const std::string& delimiters) 
{
    size_t i = m_string.find_first_not_of(delimiters, m_offset);
    if (std::string::npos == i) 
    {
        m_offset = m_string.length();
        return false;
    }

    size_t j = m_string.find_first_of(delimiters, i);
    if (std::string::npos == j) 
    {
        m_token = m_string.substr(i);
        m_offset = m_string.length();
        return true;
    }

    m_token = m_string.substr(i, j - i);
    m_offset = j;
    return true;
}

Misal:

std::vector <std::string> v;
Tokenizer s("split this string", " ");
while (s.NextToken())
{
    v.push_back(s.GetToken());
}

19

Bu, basit bir STL tek çözeltisi (~ 5 satır!) Kullanıldığı std::findve std::find_first_not_ofayrıca ön ve ayraçları arka, (boşluklar ya da örneğin dönemleri gibi) sınırlayıcı bu kolları tekrarı:

#include <string>
#include <vector>

void tokenize(std::string str, std::vector<string> &token_v){
    size_t start = str.find_first_not_of(DELIMITER), end=start;

    while (start != std::string::npos){
        // Find next occurence of delimiter
        end = str.find(DELIMITER, start);
        // Push back the token found into vector
        token_v.push_back(str.substr(start, end-start));
        // Skip all occurences of the delimiter to find new start
        start = str.find_first_not_of(DELIMITER, end);
    }
}

Canlı olarak deneyin !


3
Bu iyi bir şey ama ben birden çok sınırlayıcı ile düzgün çalışması için find () yerine find_first_of () kullanmanız gerektiğini düşünüyorum.

2
@ user755921 find_first_not_of ile başlangıç ​​konumu bulunurken birden çok sınırlayıcı atlanır.
Başlangıç

16

pystring , split yöntemi de dahil olmak üzere bir grup Python'un dize işlevini uygulayan küçük bir kütüphanedir:

#include <string>
#include <vector>
#include "pystring.h"

std::vector<std::string> chunks;
pystring::split("this string", chunks);

// also can specify a separator
pystring::split("this-string", chunks, "-");

3
Vay, sen cevap gelmiş benim acil soru ve daha bir çok soru. Bu c ++ güçlü olsun. Ancak bir dizeyi bölmek, yukarıdaki yanıtlar gibi kaynak koduyla sonuçlanırsa, açıkça cesaret kırıcıdır. Daha üst düzey dil kolaylıklarını aşağı çeken bu tür kütüphaneleri bilmek isterim.
Ross

vay, ciddiye sadece benim gün yaptın !! pystring hakkında bilmiyordum. bu bana çok zaman kazandıracak!
accraze

11

Benzer bir soru için bu cevabı gönderdim.
Tekerleği yeniden icat etme. Bir dizi kütüphane kullandım ve karşılaştığım en hızlı ve en esnek: C ++ String Toolkit Library .

İşte stackoverflow üzerinde başka bir yerde yayınladığım nasıl kullanılacağı ile ilgili bir örnek.

#include <iostream>
#include <vector>
#include <string>
#include <strtk.hpp>

const char *whitespace  = " \t\r\n\f";
const char *whitespace_and_punctuation  = " \t\r\n\f;,=";

int main()
{
    {   // normal parsing of a string into a vector of strings
       std::string s("Somewhere down the road");
       std::vector<std::string> result;
       if( strtk::parse( s, whitespace, result ) )
       {
           for(size_t i = 0; i < result.size(); ++i )
            std::cout << result[i] << std::endl;
       }
    }

    {  // parsing a string into a vector of floats with other separators
       // besides spaces

       std::string s("3.0, 3.14; 4.0");
       std::vector<float> values;
       if( strtk::parse( s, whitespace_and_punctuation, values ) )
       {
           for(size_t i = 0; i < values.size(); ++i )
            std::cout << values[i] << std::endl;
       }
    }

    {  // parsing a string into specific variables

       std::string s("angle = 45; radius = 9.9");
       std::string w1, w2;
       float v1, v2;
       if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) )
       {
           std::cout << "word " << w1 << ", value " << v1 << std::endl;
           std::cout << "word " << w2 << ", value " << v2 << std::endl;
       }
    }

    return 0;
}

8

Bu örneği kontrol edin. Size yardımcı olabilir ..

#include <iostream>
#include <sstream>

using namespace std;

int main ()
{
    string tmps;
    istringstream is ("the dellimiter is the space");
    while (is.good ()) {
        is >> tmps;
        cout << tmps << "\n";
    }
    return 0;
}

1
Yaparımwhile ( is >> tmps ) { std::cout << tmps << "\n"; }
jordix

6

MFC / ATL'nin çok güzel bir tokenizörü var. MSDN'den:

CAtlString str( "%First Second#Third" );
CAtlString resToken;
int curPos= 0;

resToken= str.Tokenize("% #",curPos);
while (resToken != "")
{
   printf("Resulting token: %s\n", resToken);
   resToken= str.Tokenize("% #",curPos);
};

Output

Resulting Token: First
Resulting Token: Second
Resulting Token: Third

1
Bu Tokenize () işlevi boş belirteçleri atlayacaktır; örneğin, ana dizede "%%" alt dizesi varsa, döndürülen boş belirteç yoktur. Atlandı.
Sheen

4

C kullanmaya hazırsanız, strtok işlevini kullanabilirsiniz . Kullanırken çoklu iş parçacığı sorunlarına dikkat etmelisiniz.


3
Strtok'un kontrol ettiğiniz dizeyi değiştirdiğini unutmayın, böylece const char * dizelerinde kopya oluşturmadan kullanamazsınız.
Graeme Perrow

9
Çok iş parçacığı sorunu, strtok'un nerede olduğunu takip etmek için global bir değişken kullanmasıdır, bu nedenle her bir strtok kullanan iki iş parçacığınız varsa, tanımlanmamış davranış elde edersiniz.
JohnMcG

@JohnMcG Ya strtok_sda temelde strtokaçık durum geçişi ile kullanın .
Matthias

4

Basit şeyler için sadece aşağıdakileri kullanıyorum:

unsigned TokenizeString(const std::string& i_source,
                        const std::string& i_seperators,
                        bool i_discard_empty_tokens,
                        std::vector<std::string>& o_tokens)
{
    unsigned prev_pos = 0;
    unsigned pos = 0;
    unsigned number_of_tokens = 0;
    o_tokens.clear();
    pos = i_source.find_first_of(i_seperators, pos);
    while (pos != std::string::npos)
    {
        std::string token = i_source.substr(prev_pos, pos - prev_pos);
        if (!i_discard_empty_tokens || token != "")
        {
            o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos));
            number_of_tokens++;
        }

        pos++;
        prev_pos = pos;
        pos = i_source.find_first_of(i_seperators, pos);
    }

    if (prev_pos < i_source.length())
    {
        o_tokens.push_back(i_source.substr(prev_pos));
        number_of_tokens++;
    }

    return number_of_tokens;
}

Korkakça feragatname: Verilerin ikili dosyalar, soketler veya bazı API çağrıları (G / Ç kartları, kameralar) aracılığıyla geldiği gerçek zamanlı veri işleme yazılımı yazıyorum. Bu işlevi hiçbir zaman başlangıçta harici yapılandırma dosyalarını okumaktan daha karmaşık veya zaman açısından kritik bir şey için kullanmam.


4

Sadece normal bir ifade kütüphanesi kullanabilirsiniz ve bunu normal ifadeler kullanarak çözebilirsiniz.

İfade (\ w +) ve değişkeni \ 1 (veya normal ifadelerin kitaplık uygulamasına bağlı olarak 1 $) kullanın.


Düzenli ifade önermek için +1, çözgü hızına ihtiyacınız yoksa, en esnek çözümdür, henüz her yerde desteklenmez, ancak zaman geçtikçe daha az önemli hale gelir.
odinthenerd

Benden +1, c ++ 11'de <regex> 'i denedim. Çok basit ve zarif
StahlRat

4

Burada çok fazla karmaşık öneri var. Bu basit std :: string çözümünü deneyin:

using namespace std;

string someText = ...

string::size_type tokenOff = 0, sepOff = tokenOff;
while (sepOff != string::npos)
{
    sepOff = someText.find(' ', sepOff);
    string::size_type tokenLen = (sepOff == string::npos) ? sepOff : sepOff++ - tokenOff;
    string token = someText.substr(tokenOff, tokenLen);
    if (!token.empty())
        /* do something with token */;
    tokenOff = sepOff;
}

4

Ben >>dize akışları üzerinde operatör ne olduğunu düşündüm :

string word; sin >> word;

1
Kötü (çok basit) bir örnek vermemdeki hatam. Bildiğim kadarıyla, bu sadece sınırlayıcınız boşluk olduğunda işe yarar.
Bill the Lizard

4

Adam Pierce'ın cevabı , bir el bükülmüş tokenizatörünün a const char*. Yineleyicilerle ilgili biraz daha sorunludur, çünkü bir stringson yineleyiciyi artırmak tanımsızdır . Bununla birlikte, string str{ "The quick brown fox" }bunu kesinlikle başarabileceğimiz göz önüne alındığında :

auto start = find(cbegin(str), cend(str), ' ');
vector<string> tokens{ string(cbegin(str), start) };

while (start != cend(str)) {
    const auto finish = find(++start, cend(str), ' ');

    tokens.push_back(string(start, finish));
    start = finish;
}

Live Example


On Freund'un önerdiği gibi standart işlevselliği kullanarak soyut karmaşıklığı arıyorsanız, strtokbasit bir seçenektir:

vector<string> tokens;

for (auto i = strtok(data(str), " "); i != nullptr; i = strtok(nullptr, " ")) tokens.push_back(i);

C ++ 17'ye erişiminiz yoksa data(str), bu örnekteki gibi değiştirmelisiniz : http://ideone.com/8kAGoa

Örnekte gösterilmemesine rağmen, strtokher belirteç için aynı sınırlayıcıyı kullanmanız gerekmez. Bu avantajla birlikte, birkaç dezavantaj var:

  1. strtokçoklu ile kullanılamaz strings, aynı zamanda: Ya bir nullptrakım tokenizing devam etmek için geçmesi gereken stringya da yeni bir char*tokenize geçmiş olması gerekir (örneğin, ancak bu destek yapmak standart olmayan uygulama vardır: strtok_s)
  2. Aynı nedenden ötürü strtokbirden çok iş parçacığında aynı anda kullanılamaz (bununla birlikte uygulama tanımlanabilir, örneğin: Visual Studio'nun uygulaması iş parçacığı için güvenlidir )
  3. Çağırma onun üzerinde çalıştığını strtokdeğiştirir, stringbu nedenle const strings, const char*s veya değişmez dizgilerde kullanılamaz, bunlardan herhangi birini tokenize etmek strtokveya stringiçeriğinin korunması gereken, strkopyalanması gerekecek bir kopya ile kopyalamak gerekir. ameliyat olmak

split_viewdizeleri tahrip edici olmayan bir şekilde tokenize etmemizi sağlar : https://topanswers.xyz/cplusplus?q=749#a874


Önceki yöntemler bir tokenize vectoryerinde üretemezler , yani başlatamadıkları yardımcı bir işleve soyutlamadan const vector<string> tokens. Bu işlevsellik ve herhangi bir beyaz boşluk sınırlayıcıyı kabul etme yeteneği bir istream_iterator. Örneğin verilen: const string str{ "The quick \tbrown \nfox" }bunu yapabiliriz:

istringstream is{ str };
const vector<string> tokens{ istream_iterator<string>(is), istream_iterator<string>() };

Live Example

istringstreamBu seçeneğin gerekli konstrüksiyonu önceki 2 seçenekten çok daha fazla maliyete sahiptir, ancak bu maliyet tipik olarak stringtahsis pahasına gizlenir .


Yukarıdaki seçeneklerden hiçbiri tokenizasyon ihtiyaçlarınız için yeterince esnek değilse, en esnek seçenek regex_token_iteratorelbette bu esneklikle kullanmaktır, daha büyük bir masraf gelir, ancak yine de bu muhtemelen stringtahsis maliyetinde gizlidir . Örneğin, aşağıdaki girdi göz önüne alındığında, kaçan virgüllere dayalı olarak da beyaz boşluk yiyerek belirtmek istiyoruz: const string str{ "The ,qu\\,ick ,\tbrown, fox" }bunu yapabiliriz:

const regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
const vector<string> tokens{ sregex_token_iterator(cbegin(str), cend(str), re, 1), sregex_token_iterator() };

Live Example


strtok_sbu arada C11 standardıdır. strtok_rbir POSIX2001 standardıdır. Her ikisi arasında, strtokçoğu platform için standart bir yeniden giriş sürümü bulunmaktadır .
Andon M. Coleman

@ AndonM.Coleman Ama bu bir c ++ sorusudur ve C ++ 'da #include <cstring>sadece c99 sürümünü içerir strtok. Benim varsayımım, bu yorumu sadece destekleyici malzeme olarak sağladığınızı ve strtokuzantıların uygulamaya özel kullanılabilirliğini gösterdiğinizi mi?
Jonathan Mee

1
Yalnızca, insanların inanabileceği kadar standart olmayan bir şey olmadığı. strtok_shem C11 tarafından hem de Microsoft'un C çalışma zamanında bağımsız bir uzantı olarak sağlanır. Burada Microsoft'un _sişlevlerinin C standardı haline geldiği ilginç bir tarih var .
Andon M. Coleman

@ AndonM.Coleman Doğru, ben seninleyim. Açıkçası, C11 standardındaysa, arayüz ve uygulama, platformdan bağımsız olarak aynı davranış gerektiren kısıtlamalara sahiptir. Şimdi tek sorun, C11 işlevinin platformlar genelinde kullanılabilir olmasını sağlamaktır. Umarım C11 standardı C ++ 17 veya C ++ 20'nin pikap için seçtiği bir şey olacaktır.
Jonathan Mee

3

Bu sorunun zaten cevaplandığını biliyorum ama katkıda bulunmak istiyorum. Belki benim çözümüm biraz basit ama ben geldi budur:

vector<string> get_words(string const& text, string const& separator)
{
    vector<string> result;
    string tmp = text;

    size_t first_pos = 0;
    size_t second_pos = tmp.find(separator);

    while (second_pos != string::npos)
    {
        if (first_pos != second_pos)
        {
            string word = tmp.substr(first_pos, second_pos - first_pos);
            result.push_back(word);
        }
        tmp = tmp.substr(second_pos + separator.length());
        second_pos = tmp.find(separator);
    }

    result.push_back(tmp);

    return result;
}

Kodumdaki bir şeye daha iyi bir yaklaşım varsa veya bir sorun varsa lütfen yorum yapın.

GÜNCELLEME: genel ayırıcı eklendi


Çözümünüzü kalabalıktan kullandı :) Kodunuzu herhangi bir ayırıcı eklemek için değiştirebilir miyim?
Zac

1
@Zac hoşunuza gittiğine sevindim ve ofc'i değiştirebilirsiniz ... sadece
cevabıma

2

Aşağıda, boş belirteçlerin (strsep gibi) dahil edilip edilmediğini (strtok gibi) kontrol etmenizi sağlayan bir yaklaşım var.

#include <string.h> // for strchr and strlen

/*
 * want_empty_tokens==true  : include empty tokens, like strsep()
 * want_empty_tokens==false : exclude empty tokens, like strtok()
 */
std::vector<std::string> tokenize(const char* src,
                                  char delim,
                                  bool want_empty_tokens)
{
  std::vector<std::string> tokens;

  if (src and *src != '\0') // defensive
    while( true )  {
      const char* d = strchr(src, delim);
      size_t len = (d)? d-src : strlen(src);

      if (len or want_empty_tokens)
        tokens.push_back( std::string(src, len) ); // capture token

      if (d) src += len+1; else break;
    }

  return tokens;
}

2

Burada hepimiz SO ile bilinçli nerds hız hiç kimse sınırlayıcı için derleme zamanı oluşturulan arama tablosu kullanan bir sürüm sunmamıştır garip görünüyor (örnek uygulama daha aşağı). Bir up tablosu kullanarak ve yineleyiciler, std :: regex'i verimlilikle geçmelidir, regex'i yenmeniz gerekmiyorsa, sadece kullanın, C ++ 11'den itibaren standardı ve süper esnek.

Bazıları zaten regex önerdi, ancak burada noobs için OP'nin tam olarak beklediği şeyi yapması gereken paketlenmiş bir örnek:

std::vector<std::string> split(std::string::const_iterator it, std::string::const_iterator end, std::regex e = std::regex{"\\w+"}){
    std::smatch m{};
    std::vector<std::string> ret{};
    while (std::regex_search (it,end,m,e)) {
        ret.emplace_back(m.str());              
        std::advance(it, m.position() + m.length()); //next start position = match position + match length
    }
    return ret;
}
std::vector<std::string> split(const std::string &s, std::regex e = std::regex{"\\w+"}){  //comfort version calls flexible version
    return split(s.cbegin(), s.cend(), std::move(e));
}
int main ()
{
    std::string str {"Some people, excluding those present, have been compile time constants - since puberty."};
    auto v = split(str);
    for(const auto&s:v){
        std::cout << s << std::endl;
    }
    std::cout << "crazy version:" << std::endl;
    v = split(str, std::regex{"[^e]+"});  //using e as delim shows flexibility
    for(const auto&s:v){
        std::cout << s << std::endl;
    }
    return 0;
}

Daha hızlı olmamız ve tüm karakterlerin 8 bit olması gerektiği kısıtlamasını kabul etmemiz gerekiyorsa, meta programlamayı kullanarak derleme zamanında bir tablo oluşturabiliriz:

template<bool...> struct BoolSequence{};        //just here to hold bools
template<char...> struct CharSequence{};        //just here to hold chars
template<typename T, char C> struct Contains;   //generic
template<char First, char... Cs, char Match>    //not first specialization
struct Contains<CharSequence<First, Cs...>,Match> :
    Contains<CharSequence<Cs...>, Match>{};     //strip first and increase index
template<char First, char... Cs>                //is first specialization
struct Contains<CharSequence<First, Cs...>,First>: std::true_type {}; 
template<char Match>                            //not found specialization
struct Contains<CharSequence<>,Match>: std::false_type{};

template<int I, typename T, typename U> 
struct MakeSequence;                            //generic
template<int I, bool... Bs, typename U> 
struct MakeSequence<I,BoolSequence<Bs...>, U>:  //not last
    MakeSequence<I-1, BoolSequence<Contains<U,I-1>::value,Bs...>, U>{};
template<bool... Bs, typename U> 
struct MakeSequence<0,BoolSequence<Bs...>,U>{   //last  
    using Type = BoolSequence<Bs...>;
};
template<typename T> struct BoolASCIITable;
template<bool... Bs> struct BoolASCIITable<BoolSequence<Bs...>>{
    /* could be made constexpr but not yet supported by MSVC */
    static bool isDelim(const char c){
        static const bool table[256] = {Bs...};
        return table[static_cast<int>(c)];
    }   
};
using Delims = CharSequence<'.',',',' ',':','\n'>;  //list your custom delimiters here
using Table = BoolASCIITable<typename MakeSequence<256,BoolSequence<>,Delims>::Type>;

Yerinde bir getNextTokenfonksiyon yapmak kolaydır:

template<typename T_It>
std::pair<T_It,T_It> getNextToken(T_It begin,T_It end){
    begin = std::find_if(begin,end,std::not1(Table{})); //find first non delim or end
    auto second = std::find_if(begin,end,Table{});      //find first delim or end
    return std::make_pair(begin,second);
}

Bunu kullanmak da kolaydır:

int main() {
    std::string s{"Some people, excluding those present, have been compile time constants - since puberty."};
    auto it = std::begin(s);
    auto end = std::end(s);
    while(it != std::end(s)){
        auto token = getNextToken(it,end);
        std::cout << std::string(token.first,token.second) << std::endl;
        it = token.second;
    }
    return 0;
}

İşte canlı bir örnek: http://ideone.com/GKtkLQ


1
Bir String sınırlayıcı ile tokenize etmek mümkün müdür?
Galigator

Bu sürüm yalnızca tek karakter sınırlayıcılar için optimize edilmiştir, bir arama tablosu kullanmak çok karakterli (dize) sınırlayıcılar için uygun değildir, bu nedenle regex'i verimlilikte yenmek daha zordur.
odinthenerd

1

boost :: make_find_iterator avantajından yararlanabilirsiniz. Buna benzer bir şey:

template<typename CH>
inline vector< basic_string<CH> > tokenize(
    const basic_string<CH> &Input,
    const basic_string<CH> &Delimiter,
    bool remove_empty_token
    ) {

    typedef typename basic_string<CH>::const_iterator string_iterator_t;
    typedef boost::find_iterator< string_iterator_t > string_find_iterator_t;

    vector< basic_string<CH> > Result;
    string_iterator_t it = Input.begin();
    string_iterator_t it_end = Input.end();
    for(string_find_iterator_t i = boost::make_find_iterator(Input, boost::first_finder(Delimiter, boost::is_equal()));
        i != string_find_iterator_t();
        ++i) {
        if(remove_empty_token){
            if(it != i->begin())
                Result.push_back(basic_string<CH>(it,i->begin()));
        }
        else
            Result.push_back(basic_string<CH>(it,i->begin()));
        it = i->end();
    }
    if(it != it_end)
        Result.push_back(basic_string<CH>(it,it_end));

    return Result;
}

1

İşte, dizeleri boşlukla ayırmak, tek ve çift tırnaklı sarılmış dizeleri hesaba katmak ve bu karakterleri sonuçlardan çıkarmak için kullanılan Swiss® Army Bıçağı. Kod snippet'inin çoğunu oluşturmak için RegexBuddy 4.x'i kullandım , ancak tırnak ve diğer bazı şeyleri soymak için özel işlem ekledim.

#include <string>
#include <locale>
#include <regex>

std::vector<std::wstring> tokenize_string(std::wstring string_to_tokenize) {
    std::vector<std::wstring> tokens;

    std::wregex re(LR"(("[^"]*"|'[^']*'|[^"' ]+))", std::regex_constants::collate);

    std::wsregex_iterator next( string_to_tokenize.begin(),
                                string_to_tokenize.end(),
                                re,
                                std::regex_constants::match_not_null );

    std::wsregex_iterator end;
    const wchar_t single_quote = L'\'';
    const wchar_t double_quote = L'\"';
    while ( next != end ) {
        std::wsmatch match = *next;
        const std::wstring token = match.str( 0 );
        next++;

        if (token.length() > 2 && (token.front() == double_quote || token.front() == single_quote))
            tokens.emplace_back( std::wstring(token.begin()+1, token.begin()+token.length()-1) );
        else
            tokens.emplace_back(token);
    }
    return tokens;
}

1
(Aşağı) oylar, oylar kadar yapıcı olabilir, ancak neden olarak yorum bırakmadığınızda değil ...
kayleeFrye_onDeck

1
Seni dışarı çıktım ama kod özellikle 'belge olmadan bir dize nasıl bölünür' googling programcı için oldukça göz korkutucu görünüyor olabilir
mattshu

Teşekkürler @mattshu! Normal olmayan segmentler onu yıldırıcı mı yoksa başka bir şey mi?
kayleeFrye_onDeck

0

Belirlenecek giriş dizesinin maksimum uzunluğu biliniyorsa, bundan faydalanılabilir ve çok hızlı bir sürüm uygulanabilir. Aşağıdaki temel fikri, hem strtok () hem de Jon Bentley'in "Programlama Perls" 2. baskısı, bölüm 15'te açıklanan "sonek dizisi" -data yapısından esinlenerek taslağı çiziyorum. Bu durumda C ++ sınıfı sadece bazı organizasyon ve kolaylık sağlar kullanım. Gösterilen uygulama, belirteçlerdeki önde gelen ve sondaki boşluk karakterlerini kaldırmak için kolayca genişletilebilir.

Temel olarak, ayırıcı karakterleri dize sonlandırıcı '\ 0' karakterleri ile değiştirebilir ve değiştirilmiş dize ile belirteçlere işaretçiler ayarlayabilirsiniz. Aşırı durumda dize yalnızca ayırıcılardan oluştuğunda, biri dize uzunluğu artı 1, boş belirteçlerle sonuçlanır. Değiştirilecek dizeyi çoğaltmak pratiktir.

Başlık dosyası:

class TextLineSplitter
{
public:

    TextLineSplitter( const size_t max_line_len );

    ~TextLineSplitter();

    void            SplitLine( const char *line,
                               const char sep_char = ',',
                             );

    inline size_t   NumTokens( void ) const
    {
        return mNumTokens;
    }

    const char *    GetToken( const size_t token_idx ) const
    {
        assert( token_idx < mNumTokens );
        return mTokens[ token_idx ];
    }

private:
    const size_t    mStorageSize;

    char           *mBuff;
    char          **mTokens;
    size_t          mNumTokens;

    inline void     ResetContent( void )
    {
        memset( mBuff, 0, mStorageSize );
        // mark all items as empty:
        memset( mTokens, 0, mStorageSize * sizeof( char* ) );
        // reset counter for found items:
        mNumTokens = 0L;
    }
};

Uygulama dosyası:

TextLineSplitter::TextLineSplitter( const size_t max_line_len ):
    mStorageSize ( max_line_len + 1L )
{
    // allocate memory
    mBuff   = new char  [ mStorageSize ];
    mTokens = new char* [ mStorageSize ];

    ResetContent();
}

TextLineSplitter::~TextLineSplitter()
{
    delete [] mBuff;
    delete [] mTokens;
}


void TextLineSplitter::SplitLine( const char *line,
                                  const char sep_char   /* = ',' */,
                                )
{
    assert( sep_char != '\0' );

    ResetContent();
    strncpy( mBuff, line, mMaxLineLen );

    size_t idx       = 0L; // running index for characters

    do
    {
        assert( idx < mStorageSize );

        const char chr = line[ idx ]; // retrieve current character

        if( mTokens[ mNumTokens ] == NULL )
        {
            mTokens[ mNumTokens ] = &mBuff[ idx ];
        } // if

        if( chr == sep_char || chr == '\0' )
        { // item or line finished
            // overwrite separator with a 0-terminating character:
            mBuff[ idx ] = '\0';
            // count-up items:
            mNumTokens ++;
        } // if

    } while( line[ idx++ ] );
}

Bir kullanım senaryosu şöyle olacaktır:

// create an instance capable of splitting strings up to 1000 chars long:
TextLineSplitter spl( 1000 );
spl.SplitLine( "Item1,,Item2,Item3" );
for( size_t i = 0; i < spl.NumTokens(); i++ )
{
    printf( "%s\n", spl.GetToken( i ) );
}

çıktı:

Item1

Item2
Item3

0

boost::tokenizerarkadaşınızdır, ancak eski / tür yerine wstring/ kullanarak uluslararası kodlama (i18n) sorunlarıyla ilgili olarak kodunuzu taşınabilir hale getirmeyi düşünün .wchar_tstringchar

#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>

using namespace std;
using namespace boost;

typedef tokenizer<char_separator<wchar_t>,
                  wstring::const_iterator, wstring> Tok;

int main()
{
  wstring s;
  while (getline(wcin, s)) {
    char_separator<wchar_t> sep(L" "); // list of separator characters
    Tok tok(s, sep);
    for (Tok::iterator beg = tok.begin(); beg != tok.end(); ++beg) {
      wcout << *beg << L"\t"; // output (or store in vector)
    }
    wcout << L"\n";
  }
  return 0;
}

"miras" kesinlikle doğru değildir ve wchar_tkesinlikle gerekli olmadıkça kimsenin kullanmaması gereken korkunç bir uygulamaya bağımlı türdür.
CoffeeandCode

Wchar_t kullanımı bir şekilde otomatik olarak herhangi bir i18n sorununu çözmez. Bu sorunu çözmek için kodlamaları kullanırsınız. Bir dizeyi ayırıcıyla böldüğünüzde, sınırlayıcının dizenin içindeki herhangi bir belirtecin kodlanmış içeriğiyle çarpışmadığı ima edilir. Kaçmak gerekebilir, vb. Wchar_t buna sihirli bir çözüm değildir.
yonil

0

Basit C ++ kodu (standart C ++ 98), birden çok ayırıcıyı kabul eder (std :: string'de belirtilir), yalnızca vektörleri, dizeleri ve yineleyicileri kullanır.

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept> 

std::vector<std::string> 
split(const std::string& str, const std::string& delim){
    std::vector<std::string> result;
    if (str.empty())
        throw std::runtime_error("Can not tokenize an empty string!");
    std::string::const_iterator begin, str_it;
    begin = str_it = str.begin(); 
    do {
        while (delim.find(*str_it) == std::string::npos && str_it != str.end())
            str_it++; // find the position of the first delimiter in str
        std::string token = std::string(begin, str_it); // grab the token
        if (!token.empty()) // empty token only when str starts with a delimiter
            result.push_back(token); // push the token into a vector<string>
        while (delim.find(*str_it) != std::string::npos && str_it != str.end())
            str_it++; // ignore the additional consecutive delimiters
        begin = str_it; // process the remaining tokens
        } while (str_it != str.end());
    return result;
}

int main() {
    std::string test_string = ".this is.a.../.simple;;test;;;END";
    std::string delim = "; ./"; // string containing the delimiters
    std::vector<std::string> tokens = split(test_string, delim);           
    for (std::vector<std::string>::const_iterator it = tokens.begin(); 
        it != tokens.end(); it++)
            std::cout << *it << std::endl;
}
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.