2014-06-26 13 views
21

Mi sono imbattuto nel seguente codice ma ho bisogno di aiuto per capire il codice. Supponiamo che la stringa s abbia spazi su entrambi i lati.Spiegazione di una funzione di rifilatura di stringhe

string trim(string const& s){ 
    auto front = find_if_not(begin(s), end(s), isspace); 
    auto back = find_if_not(rbegin(s), rend(s), isspace); 
    return string { front, back.base() }; 
} 

L'autore ha dichiarato che i punti di ritorno alla fine dell'ultimo spazio mentre il fronte punta al primo carattere di spazio non bianco. Quindi back.base() è stato chiamato ma non capisco perché.

Anche cosa rappresentano le parentesi graffe, seguendo la stringa nell'istruzione di reso?

+4

A parte il profiling dell'intera faccenda, questo in realtà sembra un bel pezzo di codice. – Niall

+8

Questo codice si arresta in modo anomalo su input costituiti da uno o più caratteri di spaziatura, poiché gli iteratori si incroceranno. –

+0

@j_random_hacker Concordo. ha bisogno di una valvola di sicurezza per garantire che 'back.base()' sia maggiore di 'front', altrimenti basta restituire la stringa vuota.Mi piace ancora l'idea in linea di principio. Penso che in realtà genererà un'eccezione di lunghezza perché il risultato di 'last' -' first' sarà negativo. – WhozCraig

risposta

28

Le parentesi rappresentano la nuova inizializzazione di C++ 11.

.base() e invertire iteratori

Il .base() è quello di recuperare l'all'iteratore sottostante (back è un reverse_iterator), per costruire correttamente la nuova stringa da un intervallo valido.

Una foto. posizioni iteratore normali di una stringa (è un po 'più complesso di questo per quanto riguarda come rend() opere, ma concettualmente comunque ...)

 begin         end 
      v         v 
     ------------------------------------- 
     | sp | sp | A | B | C | D | sp | sp | 
     ------------------------------------- 
    ^        ^
    rend        rbegin 

Una volta che i due cicli trovare finire, il risultato di tali iteratori in questa sequenza sarà essere posizionato a:

    front 
        v 
     ------------------------------------- 
     | sp | sp | A | B | C | D | sp | sp | 
     ------------------------------------- 
           ^
           back 

dovessimo prendere solo quei iteratori e costruire una sequenza da loro (che non possiamo, in quanto non sono corrispondenti tipi, ma a prescindere, supposto che potrebbe), il risultato sarebbe essere "copia a partire da A, fermandosi a D" ma non includerebbe D nei dati risultanti .

Immettere il membro back() di un iteratore inverso. Restituisce un iteratore non inverso della classe iteratore in avanti, posizionato sull'elemento "accanto a" l'iteratore posteriore; vale a dire

    front 
        v 
     ------------------------------------- 
     | sp | sp | A | B | C | D | sp | sp | 
     ------------------------------------- 
            ^
           back.base() 

Ora quando copiamo la nostra gamma { front, back.base() } copiamo a partire da A e fermarsi al primo spazio (ma non la comprende), tra cui in tal modo la D avremmo perso.

È in realtà un piccolo pezzo di codice, btw.

Alcuni ulteriore controllo

aggiunto alcuni controlli di base al codice originale.

Nel tentativo di mantenere lo spirito del codice originale (utilizzo di C++ 1y/C++ 14), aggiungendo alcuni controlli di base per le stringhe di spazio vuoto e solo bianco;

string trim_check(string const& s) 
{ 
    auto is_space = [](char c) { return isspace(c, locale()); }; 
    auto front = find_if_not(begin(s), end(s), is_space); 
    auto back = find_if_not(rbegin(s), make_reverse_iterator(front), is_space); 
    return string { front, back.base() }; 
} 
+2

Vale la pena notare che l'iteratore 'base()' fa riferimento all'elemento * accanto a * che fa riferimento all'iteratore inverso. In questo caso, in qualche modo sinonimi di 'std :: next (indietro)', ma non nella direzione opposta, piuttosto nella direzione "avanti" della sequenza sottostante. – WhozCraig

+2

@WhozCraig Sì. Come riferimento aggiuntivo http://en.cppreference.com/w/cpp/iterator/reverse_iterator contiene una bella annotazione sul 'reverse_iterator'. – Niall

+0

Grazie per i tuoi commenti, ma perché punta in primo piano il primo carattere non di spaziatura, ma il dorso non punta all'ultimo carattere non spaziale? – Smithy