2015-07-01 17 views
12

Potrzebuję utworzyć parser string w C++. Próbowałem za pomocąTokenizer ciągów z wieloma ogranicznikami, w tym ogranicznikiem bez zwiększenia

vector<string> Tokenize(const string& strInput, const string& strDelims) 
{ 
vector<string> vS; 

string strOne = strInput; 
string delimiters = strDelims; 

int startpos = 0; 
int pos = strOne.find_first_of(delimiters, startpos); 

while (string::npos != pos || string::npos != startpos) 
{ 
    if(strOne.substr(startpos, pos - startpos) != "") 
    vS.push_back(strOne.substr(startpos, pos - startpos)); 

    // if delimiter is a new line (\n) then add new line 
    if(strOne.substr(pos, 1) == "\n") 
    vS.push_back("\\n"); 
    // else if the delimiter is not a space 
    else if (strOne.substr(pos, 1) != " ") 
    vS.push_back(strOne.substr(pos, 1)); 

    if(string::npos == strOne.find_first_not_of(delimiters, pos)) 
    startpos = strOne.find_first_not_of(delimiters, pos); 
    else 
    startpos = pos + 1; 

     pos = strOne.find_first_of(delimiters, startpos); 

} 

return vS; 
} 

Działa to na 2x + 7cos (3Y)

(tokenizer("2X+7cos(3Y)","+-/^() \t");)

Ale daje błąd wykonania dla 2X

muszę non rozwiązanie impuls.

Próbowałem za pomocą C++ String Toolkit (StrTk) Tokenizer

std::vector<std::string> results; 
strtk::split(delimiter, source, 
      strtk::range_to_type_back_inserter(results), 
      strtk::tokenize_options::include_all_delimiters); 

return results; 

ale nie daje znak jako osobny ciąg.

np: jeśli dam wejście jako 2X + 3Y

wyjściowy wektor zawiera

2X +

3Y

+0

Przypuszczalnie trzeba chronić 'pos = str.find_first_of (separatory, lastPos)' od przypadku, gdy 'lastPos' jest' npos'. – ooga

+0

Jeśli zamierzasz wyświetlać kod przy użyciu biblioteki innej niż standardowa (pozornie [to] (http://www.codeproject.com/Articles/23198/C-String-Toolkit-StrTk-Tokenizer), powinieneś nazwać to w pytaniu podaj link i zastanów się nad dodaniem powiązanego tagu do swojego pytania: –

+3

Dodaję, że strtk, ponieważ powiedzenie, że rozwiązanie nie było w stanie rozwiązać mojego problemu. Doda link teraz – user2473015

Odpowiedz

1

wyjście Loop warunek jest łamane:

while (string::npos != pos || string::npos != startpos) 

Umożliwia wejście z, powiedzmy pos = ONP i startpos = 1.

Więc

strOne.substr(startpos, pos - startpos) 
strOne.substr(1, npos - 1) 

końcowy jest nie ONP, więc nie robi substr zatrzymaj się tam, gdzie powinien i BUM!

Jeśli pos = ONP i pozycja_początkowa = 0,

strOne.substr(startpos, pos - startpos) 

życiu, ale

strOne.substr(pos, 1) == "\n" 
strOne.substr(npos, 1) == "\n" 

umiera.Tak więc

strOne.substr(pos, 1) != " " 
Niestety nie jestem w stanie rozwiązać tego problemu, ale QuestionC ma dobry pomysł. Lepsze filtrowanie. Coś wzdłuż linii:

if (string::npos != pos) 
    { 
     if (strOne.substr(pos, 1) == "\n") // can possibly simplify this with strOne[pos] == '\n' 
      vS.push_back("\\n"); 
     // else if the delimiter is not a space 
     else if (strOne[pos] != ' ') 
      vS.push_back(strOne.substr(pos, 1)); 
    } 
2

Co prawdopodobnie dzieje się to upaść, gdy przeszedł npos:

lastPos = str.find_first_not_of(delimiters, pos); 

Po prostu dodaj przerwy dla Ciebie ur pętli zamiast polegać na klauzuli while, aby się z niej wyrwać.

if (pos == string::npos) 
    break; 
lastPos = str.find_first_not_of(delimiters, pos); 

if (lastPos == string::npos) 
    break; 
pos = str.find_first_of(delimiters, lastPos); 
0

stworzyłem małą funkcję, która dzieli ciąg na podciągi (które są przechowywane w wektorze) i pozwala na ustawienie znaków, które chcesz traktować jako spacji. Normalne białe znaki będą nadal traktowane jako białe znaki, więc nie musisz tego definiować. W rzeczywistości wszystko, co robi, zmienia postać, którą zdefiniowałeś jako białą spację w rzeczywistą białą spację (space char ''). Następnie uruchamia to w strumieniu (stringstream), aby oddzielić podciągi i zapisać je w wektorze. Może nie być to, czego potrzebujesz do tego konkretnego problemu, ale może może dać ci kilka pomysłów.

// split a string into its whitespace-separated substrings and store 
// each substring in a vector<string>. Whitespace can be defined in argument 
// w as a string (e.g. ".;,?-'") 
vector<string> split(const string& s, const string& w) 
{ 
    string temp{ s }; 
    // go through each char in temp (or s) 
    for (char& ch : temp) {  
     // check if any characters in temp (s) are whitespace defined in w 
     for (char white : w) { 
      if (ch == white) 
       ch = ' ';  // if so, replace them with a space char (' ') 
     } 
    } 

    vector<string> substrings; 
    stringstream ss{ temp }; 

    for (string buffer; ss >> buffer;) { 
     substrings.push_back(buffer); 
    } 
    return substrings; 
} 
+1

Ciekawe, ale bardzo ciężkie na brute force. Czy rozważałeś użycie 'set' zamiast' string' w? Możesz zredukować 'for (char white: w)' loop to 'if (w.find (ch)! = w.end ()) 'Niesamowite, ale nie N-kwadratowe – user4581301

+0

Hmm ... Nie myślałem o tym. Szczerze mówiąc, jestem całkiem nowy dla C++ i programowania w ogóle, więc jest wiele rzeczy, których nie wiem. Muszę jednak spróbować i przetestować działanie obu sposobów. Zgadzam się, że sposób, w jaki teraz to robię, jest ciężki ... Hej, działa to jednak. wypróbować inny, bardziej efektywny sposób. Dziękuję za komentarz. –

0

Byłoby wspaniale, gdybyś mógł podzielić się informacjami na temat swojego środowiska. Twój program działał poprawnie z wartością wejściową 2X na mojej Fedorze 20 używając g ++.

+1

Ta odpowiedź jest bardziej odpowiednia jako komentarz i tak naprawdę nie jest odpowiedzią na pytanie – SteveFerg

+0

Jestem w Win 8.1 z kompilatorem MinGW C++ – user2473015

Powiązane problemy