2011-01-15 8 views
5

Ecco cosa sto cercando di fare:Modifica comportamento di virgolette quando >> a stringstream

dire che ho uno stringstream. Poi ho << "\"hello world\" today";

poi quando faccio

sstr >> myString1 >> myString2; 

vorrei myString1 avere "ciao mondo" e per myString2 di avere "oggi"

Esiste un modo, possibilmente con un manipolatore , Per realizzare questo?

Grazie

risposta

4

No.

vi sia bisogno di cambiare il tipo di flusso (e quindi la semantica di analisi) o utilizzare il proprio tipo stringa (e quindi modificare la semantica di analisi nel vostro op sovraccarico >>) .

Invece, non crei una funzione, simile a getline, che analizza una "parola" forse-citato da un torrente:

getqword(sstr, myString1); 
getqword(sstr, myString2); 
if (sstr) { /* both succeeded */ } 

Nota che l'input in uno std :: string termina già a spazi bianchi, così avete solo bisogno di gestire sbirciare in anticipo per un preventivo e quindi gestire casi limite, di cui ci sono molti:

  • fughe (tra virgolette virgolette)
    • i tre stili prevalenti sono di quotato, rovesciato e virgolettato; ognuno ha vantaggi e svantaggi
  • si estende su più linee (può \ n essere inclusi?)
    • questo è spesso un errore nei dati, in modo da non permettere che possa essere di grande aiuto in alcune circostanze
  • cosa succede se una parola citata finisce accanto a un'altra parola?
    • "\"hello world\"today"
  • saltare gli spazi restanti?
    • differenza getline, ha senso per onorare il flusso skipws bandiera, ma ho potuto vedere che andare nella direzione opposta in rare circostanze
    • la sentinella istream gestirà questo per voi
  • non dimenticare usare i tratti del flusso e le impostazioni locali, o usare metodi che già lo fanno!
    • o documentare i presupposti
+0

È facile da implementare con std :: getline (istream, stringa, terminatore). Basta impostare il terminatore su "" "e smetterà di leggerlo al primo: –

+0

@Martin: Dipende da decisioni specifiche per l'escape e la gestione della linea che non si desidera sempre –

+0

Non sai cosa intendi. nella tua risposta: –

1

Nope. Non quel modo particolare. Potresti creare un "typedef forte" per la stringa e progettare un nuovo operatore >> per esso che si comporta in questo modo.

0

Questo non è possibile.E 'perché se si guarda nella realizzazione di operator>> per basic_istream che è in realtà chiamato quando fate sstr >> myString1, si vedrà questo all'interno del ciclo for:

else if (_Ctype_fac.is(_Ctype::space,_Traits::to_char_type(_Meta))) 
    break;// whitespace, quit 

mezzi, una volta che si ottiene "spazio", Quit. Quindi non puoi continuare ad aggiungere caratteri al tuo myString1 una volta che hai spazio.

Nota che questa è l'implementazione MSVC++, ma sono sicuro che l'equivalente verrà trovato in tutte le implementazioni!

2

Non direttamente, è necessaria una classe "wrapper" che termina dove si desidera.

struct QuotedStringReader 
{ 
    std::string& str; 
    QuotedStringReader(std::string& s) : str(s) {} 
}; 

std::istream operator>>(std::istream&, const QuotedStringReader& qsr); 

std::string s, s2; 
stream >> QuotedStringReader(s) << s2; 

Si noti che si tratta di una rara occasione in cui lo streaming in un const - perché si può scrivere al str interna anche se è const, e in questo modo posso passare in una temporanea.

In realtà, come probabilmente non sai cosa stai per leggere, puoi semplicemente chiamarlo "TokenReader" che legge ciò che definisci come "token".

5

Risposta breve: No

lungo Risposta:
Non ci sono manipola che lo farà per voi.

risposta alternativa:

Si potrebbe scrivere il proprio tipo che potrebbe essere utilizzato in combinazione con gli operatori del flusso di fare eseguire questa operazione.

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


class QuotedWord 
{ 
    public: 
     operator std::string const&() const { return data;} 

    private: 
     std::string  data; 
     friend std::ostream& operator<<(std::ostream& str, QuotedWord const& value); 
     { 
     return str << value.data; 
     } 
     friend std::istream& operator>>(std::istream& str, QuotedWord& value); 
     { 
     char x; 
     str >> x; 
     if ((str) && (x == '"')) 
     { 
      std::string extra; 
      std::getline(str, extra, '"'); 
      value.data = std::string("\"").append(extra).append("\""); 
     } 
     else 
     { 
      str.putback(x); 
      str >> value.data; 
     } 
     return str; 
     } 
}; 

Quindi può essere utilizzato normalmente.

int main() 
{ 
    QuotedWord word; 

    std::cin >> word; 
    std::cout << word << "\n"; 

    // Easily convertible to string 
    std::string tmp = word; 
    std::cout << tmp << "\n" 

    // because it converts to a string easily it can be used where string is needed. 
    std::vector<std::string> data; 

    std::copy(std::istream_iterator<QuotedWord>(std::cin), 
       std::istream_iterator<QuotedWord>(), 

       // Notice we are using a vector of string here. 
       std::back_inserter(data) 
      ); 
} 

> ./a.out 
"This is" a test // Input 
"This is"   // Output 
"This is" 
+0

Non gestisce il caso di "input" '(non ci sono spazi bianchi tra virgolette) o' 'input' more', che, se implementato in questo modo, richiede più dell'unica restituzione garantita. –

+0

Hai dimenticato di controllare se str >> x è riuscito o fallito e devi saltare whitespace se è impostato skipws, che è più semplice con una sentry istream, altrimenti è molto vicino a ciò che stavo immaginando nella mia risposta: –

+0

@Fred Nurk: tutto risolto. Grazie al codice preso da @ Christian Ammer: http://stackoverflow.com/questions/4701535/changing-behaviour-of-double-quotes-when-a-stringstream/4701684#4701684 –

0

È possibile sovraccaricare l'operatore di flusso di input e includere la semantica di analisi lì.

std::istream& operator>>(std::istream& is, std::string& out) 
{ 
    char c; 
    is >> c; 
    if (c == '\"') 
    { 
     std::getline(is, out, '\"'); 
     return is; 
    } 
    else 
    { 
     is.putback(c); 
     return std::operator >>(is, out); 
    } 
} 

int main() 
{ 
    std::istringstream iss("\"hello world\" today"); 
    std::string test; 
    while (iss >> test) 
     std::cout << test << std::endl; 
} 
+1

Anche se questo funziona. Non mi piace perché porta a un comportamento inaspettato. Cosa succede se un collega modifica il codice senza sapere che è stato definito un nuovo overload dell'operatore >> per la stringa.Il problema potrebbe non comparire nemmeno durante i suoi test unitari ma esplodere nel mondo reale. –

+0

Non dovresti sovraccaricare gli operatori sui tipi di stdlib in cui un tuo tipo non è coinvolto. –

Problemi correlati