2015-06-12 17 views
5

Próbuję podzielić ciąg i umieścić go w wektorzedzielenie ciąg ale utrzymanie pustych żetony C++

jednak, ja też chce mieć pusty znak, gdy istnieje kolejny separator:

Na przykład :

string mystring = "::aa;;bb;cc;;c" 

Chciałbym tokenize ten ciąg na:; ograniczniki , ale pomiędzy ogranicznikami takimi jak :: i ;; Chciałbym wepchnąć mój wektor pusty ciąg;

so my desired output for this string is: 

"" (empty) 
aa 
"" (empty) 
bb 
cc 
"" (empty) 
c 

Również moim wymaganiem nie jest użycie biblioteki boost.

jeśli ktokolwiek mógł mi pomóc.

dzięki

kod który tokenize ciąg, ale nie obejmuje pustych znaków

void Tokenize(const string& str,vector<string>& tokens, const string& delim) 
{ 
     // Skip delimiters at beginning. 
    string::size_type lastPos = str.find_first_not_of(delimiters, 0); 
    // Find first "non-delimiter". 
    string::size_type pos  = str.find_first_of(delimiters, lastPos); 

while (string::npos != pos || string::npos != lastPos) 
{ 
    // Found a token, add it to the vector. 
    tokens.push_back(str.substr(lastPos, pos - lastPos)); 
    // Skip delimiters. Note the "not_of" 
    lastPos = str.find_first_not_of(delimiters, pos); 
    // Find next "non-delimiter" 
    pos = str.find_first_of(delimiters, lastPos); 
    } 
} 
+1

próbowałeś coś? – Amit

+0

Próbowałem powyższego kodu do tokenizacji mojego ciągu znaków, który działa, ale tylko wyklucza puste tokeny. – XDProgrammer

+0

Dlaczego nie dodajemy 'tokens.push_back (" ");' zaraz po 'tokens.push_back (str.substr (lastPos, pos - lastPos)); '? – Bastien

Odpowiedz

4

Można zrobić swoją pracę algorytmu z kilku prostych zmian. Po pierwsze, nie pomijaj ograniczników na początku, a zamiast pomijać ograniczniki w środku ciągu, wystarczy zwiększyć pozycję o jeden. Ponadto, sprawdzanie npos powinno zapewnić, że oba pozycje nie są , więc powinno być && zamiast ||.

void Tokenize(const string& str,vector<string>& tokens, const string& delimiters) 
{ 
    // Start at the beginning 
    string::size_type lastPos = 0; 
    // Find position of the first delimiter 
    string::size_type pos = str.find_first_of(delimiters, lastPos); 

    // While we still have string to read 
    while (string::npos != pos && string::npos != lastPos) 
    { 
     // Found a token, add it to the vector 
     tokens.push_back(str.substr(lastPos, pos - lastPos)); 
     // Look at the next token instead of skipping delimiters 
     lastPos = pos+1; 
     // Find the position of the next delimiter 
     pos = str.find_first_of(delimiters, lastPos); 
    } 

    // Push the last token 
    tokens.push_back(str.substr(lastPos, pos - lastPos)); 
} 
+0

* "// Znajdź następny" bez ogranicznika "* nie opisuje tego, co' pos = str.find_first_of (ograniczniki, lastPos); 'robi, i nie dodajesz tokena po ostatnim separatorze (lub' ' 'bez żadnego ogranicznika) Generowanie podejścia brzmi jednak. –

+0

Nie powinieneś dodawać' tokens.push_back (str.substr (lastPos, pos-lastPos)); 'na końcu, aby dodać ostatni ciąg jeśli nie jest pusty? – Bastien

+0

, naprawiony .. – TartanLlama

2

Mam wersję używając iteratory:

std::vector<std::string> split_from(const std::string& s 
    , const std::string& d, unsigned r = 20) 
{ 
    std::vector<std::string> v; 
    v.reserve(r); 

    auto pos = s.begin(); 
    auto end = pos; 

    while(end != s.end()) 
    { 
     end = std::find_first_of(pos, s.end(), d.begin(), d.end()); 
     v.emplace_back(pos, end); 
     pos = end + 1; 
    } 

    return v; 
} 

Używanie interfejsu:

void Tokenize(const std::string& s, std::vector<std::string>& tokens 
    , const std::string& delims) 
{ 
    auto pos = s.begin(); 
    auto end = pos; 

    while(end != s.end()) 
    { 
     end = std::find_first_of(pos, s.end(), delims.begin(), delims.end()); 
     tokens.emplace_back(pos, end); 
     pos = end + 1; 
    } 
} 
+0

bardzo ładnie znacznie bardziej uproszczone .. dzięki – XDProgrammer