2009-05-20 15 views
8

Sono nuovo alla programmazione. Ho cercato di scrivere una funzione in C++ che sfrutta il contenuto di una stringa in una matrice di stringhe in un determinato parametro, ad esempio:Come posso dividere una stringa con un delimitatore in una matrice?

string str = "___this_ is__ th_e str__ing we__ will use__"; 

dovrebbe restituire matrice di stringhe:

cout << stringArray[0]; // 'this' 
cout << stringArray[1]; // ' is' 
cout << stringArray[2]; // ' th' 
cout << stringArray[3]; // 'e str' 
cout << stringArray[4]; // 'ing we' 
cout << stringArray[5]; // ' will use' 

posso tokenize la stringa va bene, ma la parte più difficile per me è come posso specificare il numero di elementi in stringArray prima di assegnargli la stringa corrente e anche come restituire stringArray dalla funzione.

Qualcuno potrebbe mostrarmi come scrivere la funzione?

Edit1: Non ho necessariamente bisogno che i risultati siano in array di stringhe qualsiasi contenitore che posso chiamare come variabile regolare con una sorta di indicizzazione.

+0

Compito a casa, per caso? Va bene, certo, ma io vengo dalla risposta alle domande dei compiti in modo diverso dalla folla ... – dmckee

+0

duplicato: http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c – lothar

+0

@ Le risposte Iothar qui sembrano essere più efficienti. – Arnthor

risposta

10

Ecco il mio primo tentativo di questo utilizzando vettori e stringhe:

vector<string> explode(const string& str, const char& ch) { 
    string next; 
    vector<string> result; 

    // For each character in the string 
    for (string::const_iterator it = str.begin(); it != str.end(); it++) { 
     // If we've hit the terminal character 
     if (*it == ch) { 
      // If we have some characters accumulated 
      if (!next.empty()) { 
       // Add them to the result vector 
       result.push_back(next); 
       next.clear(); 
      } 
     } else { 
      // Accumulate the next character into the sequence 
      next += *it; 
     } 
    } 
    if (!next.empty()) 
     result.push_back(next); 
    return result; 
} 

Speriamo che questo ti dà una sorta di idea di come fare per questo.Sul tuo esempio stringa restituisce i risultati corretti con questo codice di prova:

int main (int, char const **) { 
    std::string blah = "___this_ is__ th_e str__ing we__ will use__"; 
    std::vector<std::string> result = explode(blah, '_'); 

    for (size_t i = 0; i < result.size(); i++) { 
     cout << "\"" << result[i] << "\"" << endl; 
    } 
    return 0; 
} 
+1

Il primo parametro da esplodere() dovrebbe essere un riferimento costante. Il compilatore quindi si lamenterà, quindi 'esso' deve essere una stringa :: const_iterator. – ralphtheninja

+0

@Magnus: Grazie, ha aggiunto quella correzione :) –

+1

Dovresti controllare se 'next' non è vuoto e in tal caso aggiungerlo ai risultati DOPO IL LOOP. Altrimenti, l'ultimo elemento dopo il carattere di esplosione non sarà contenuto. – ddinchev

1

Se ti ostini a fare stringArray un array come oppossed ad un std::vector<> (che sarebbe la cosa giusta da fare) si deve a uno:

  1. Fare due passaggi (uno a contare, si vede)
  2. Implementare un array dinamico autonomamente.

L'utilizzo di un vettore è più semplice vector::push_back() aggiunge nuove cose alla fine. Quindi:

vector* explode(string s){ 
    vector<string> *v = new vector<string> 
    //... 
    // in a loop 
    v->push_back(string_fragment); 
    //... 
    return v; 
} 

non necessaria dopo tutto Left in per completezza.

Per restituire l'array di stringhe si utilizza char **.

Come in

char ** explode(const char *in){ 
    ... 

} 

BTW-- Come sarà la funzione chiamante sapere quanti elementi sono nella matrice restituita? Dovrai risolvere anche questo. Utilizzare std::vector<> a meno che non siano vincolati da forze esterne ...

+0

v-> push_back (string_fragment); – ralphtheninja

+0

@Magnus: Oops. Grazie. – dmckee

+0

Penso che passare di nuovo un vettore assegnato allo stack o prendere un riferimento a un vettore da riempire sarebbe una scelta migliore, quindi allocare un vettore non elaborato nella funzione, quindi passare la responsabilità dell'eliminazione al client. – GManNickG

1

È possibile utilizzare un vettore di stringa (std::vector<std::string>), aggiungere ogni token ad esso con push_back e quindi restituirlo dalla funzione tokenize.

1

Usa std :: vector come array dinamico e restituiscilo come risultato.

1

Forse dovresti usare una lista invece di una matrice. In questo modo non avresti bisogno di conoscere il numero di elementi prima del tempo. Si può anche prendere in considerazione l'utilizzo dei contenitori STL.

8

Utilizzando STL (mi spiace non compilatore non testato)

#include <vector> 
#include <string> 
#include <sstream> 

int main() 
{ 
    std::vector<std::string> result; 

    std::string str = "___this_ is__ th_e str__ing we__ will use__"; 

    std::stringstream data(str); 

    std::string line; 
    while(std::getline(data,line,'_')) 
    { 
     result.push_back(line); // Note: You may get a couple of blank lines 
           // When multiple underscores are beside each other. 
    } 
} 

// o definire un gettone

#include <vector> 
#include <string> 
#include <iterator> 
#include <algorithm> 
#include <sstream> 

struct Token: public std::string // Yes I know this is nasty. 
{         // But it is just to demosntrate the principle.  
}; 

std::istream& operator>>(std::istream& s,Token& t) 
{ 
    std::getline(s,t,'_'); 

    // *** 
    // Remove extra '_' characters from the stream. 
    char c; 
    while(s && ((c = s.get()) != '_')) {/*Do Nothing*/} 
    if (s) 
    { 
     s.unget(); // Put back the last char as it is not '_' 
    } 
    return s; 
} 

int main() 
{ 
    std::vector<std::string> result; 

    std::string str = "___this_ is__ th_e str__ing we__ will use__"; 

    std::stringstream data(str); 

    std::copy(std::istream_iterator<Token>(data), 
       std::istream_iterator<Token>() 
       std::back_inserter(result) 
      ); 
} 
+0

Quindi aggiungi il segno di spunta nel ciclo while per saltare le "linee" vuote. – jmucchiello

+1

Questo è un esercizio per l'utente. –

0

Attendi fino a quando la tua struttura di dati non viene classificata e quindi codificale con un elenco collegato. Se è per i compiti, però, si può essere in grado di farla franca, solo l'array è molto grande.

0

Il codice qui sotto:

template <typename OutputIterator> 
int explode(const string &s, const char c, OutputIterator output) { 
    stringstream data(s); 
    string line; 
    int i=0; 
    while(std::getline(data,line,c)) { *output++ = line; i++; } 
    return i; 
} 

int main(...) { 
    string test="H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0"; 
    cout << test << endl; 
    vector<string> event; 
**This is the main call** 
    int evts = explode(test,':', back_inserter(event)); 
    for (int k=0; k<evts; k++) 
    cout << event[k] << "~"; 
    cout << endl; 
} 

uscite

H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0 
H~AMBV4~2~182.45~182.45~182.45~182.45~182.41~32~17700~3229365~201008121711~0~ 
2

Funziona per me:

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

using namespace std; 

vector<string> explode(const string &delimiter, const string &explodeme); 

int main(int argc, char *argv[]) 
{ 
    string str = "I have a lovely bunch of cocoa nuts"; 
    cout<<str<<endl; 
    vector<string> v = explode(" ", str); 
    for(int i=0; i<v.size(); i++) 
     cout <<i << " ["<< v[i] <<"] " <<endl; 
} 

vector<string> explode(const string &delimiter, const string &str) 
{ 
    vector<string> arr; 

    int strleng = str.length(); 
    int delleng = delimiter.length(); 
    if (delleng==0) 
     return arr;//no change 

    int i=0; 
    int k=0; 
    while(i<strleng) 
    { 
     int j=0; 
     while (i+j<strleng && j<delleng && str[i+j]==delimiter[j]) 
      j++; 
     if (j==delleng)//found delimiter 
     { 
      arr.push_back( str.substr(k, i-k)); 
      i+=delleng; 
      k=i; 
     } 
     else 
     { 
      i++; 
     } 
    } 
    arr.push_back( str.substr(k, i-k)); 
    return arr; 
} 

fonte:http://www.zedwood.com/article/106/cpp-explode-function

0

Ecco il mio codice di cottura (completo). Può essere utile per alcuni con lo stesso bisogno.

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

int main(){ 
     std::string s = "scott:tiger:mushroom"; 
     std::string delimiter = ":"; 

     std::vector<std::string> outputArr; 
     size_t pos = 0; 
     std::string token; 
     while ((pos = s.find(delimiter)) != std::string::npos) { 
      token = s.substr(0, pos); 
      s.erase(0, pos + delimiter.length()); 
      outputArr.push_back(token); 
     } 
     outputArr.push_back(s); 

     // Printing Array to see the results 
     std::cout<<"====================================================================================\n"; 
     for (int i=0;i<outputArr.size();i++){ 
       std::cout<<outputArr[i]<<"\n"; 
     } 
     std::cout<<"====================================================================================\n"; 
} 

Cheers !!

0

Penso di aver scritto una soluzione molto più semplice.

std::vector<std::string> explode(const std::string& string, const char delimiter) { 

std::vector<std::string> result; 
unsigned int start = 0, pos = 0; 

while (pos != string.length()) { 
    if (string.at(pos) == delimiter || pos + 1 == string.length()) { 
     unsigned int size = (pos - start) + ((pos + 1) == string.length() ? 1 : 0); 
     if (size != 0) { // Make this 'if' as a option? like a parameter with removeEmptyString? 
      result.push_back(string.substr(start, size)); 
     } 
     start = pos + 1; 
    } 
    pos++; 
} 

return std::move(result); 

}

0

questo ha funzionato per me:

#include <iostream> 
#include <vector> 
#include <string> 
#include <sstream> 

using namespace std; 

vector<string> split(string str, char delimiter) { 
    vector<string> internal; 
    stringstream ss(str); // Turn the string into a stream. 
    string tok; 

    while(getline(ss, tok, delimiter)) { 
    internal.push_back(tok); 
    } 

    return internal; 
} 

int main(int argc, char **argv) { 
    string myCSV = "one,two,three,four"; 
    vector<string> sep = split(myCSV, ','); 

    // If using C++11 (which I recommend) 
    /* for(string t : sep) 
    * cout << t << endl; 
    */ 

    for(int i = 0; i < sep.size(); ++i) 
    cout << sep[i] << endl; 
} 

Fonte: http://code.runnable.com/VHb0hWMZp-ws1gAr/splitting-a-string-into-a-vector-for-c%2B%2B

Problemi correlati