Newsgroup: it.comp.lang.c++
Titolo: StringTokenizer

Chi conosce java...
In ogni caso: esiste nella libreria standard qualcosa del genere?
StringTokenizer tok=new StringTokenizer("cia-cia-cia","-");
while (tok.hasMoreTokens()){
      System.out.println(tok.nextToken());
}
Output:
cia
cia
cia

 
No. (Beh, ci sarebbe strtok, ma č meglio lasciarlo stare.)
Installati la libreria di Boost e usa questo:
 
http://www.boost.org/libs/tokenizer/index.htm
Max

 > In ogni caso: esiste nella libreria standard qualcosa del genere?
Ho tradotto pochi giorni fa questa classe in C++. Il funzionamento è
perfettamente identico alla classe documentata in Java.
/*
 * @(#)StringTokenizer.h 14.52 24/02/03
 *
 * Liberamente tradotta e modificata a partire dai sorgenti del
 * JDK 1.4.1_02. Distribuibile secondo la licenza originale Sun.
 */
#ifndef STRINGTOKENIZER_H
#define STRINGTOKENIZER_H
#include <string>
/**
 * \brief La classe StringTokenizer permette ad un'applicazione di
suddividere
 * una stringa in tokens.
 *
 * Il set di delimitatori (i caratteri che separano i token) possono essere
 * specificati sia al momento della creazione dell'oggetto sia
dinamicamente,
 * token per token.
 *
 * Un'istanza di <code>StringTokenizer</code> si comporta in uno dei due
modi
 * seguenti, dipendentemente da come è stata creata con il flag
 * <code>returnDelims</code> che può assumere i valori <code>true</code>
oppure
 * <code>false</code>:
 * <ul>
 * <li>Se il flag è <code>false</code>, i caratteri delimitatori servono per
 *     dividere i token. Un token, dunque, è una massima sequenza di
caratteri
 *     consecutivi che non sono delimitatori.
 * <li>Se il flag è <code>true</code>, i carateri delimitatori sono essi
stessi
 *     considerati tokens. Un token è pertanto un carattere delimitatore
oppure
 *     una massima sequenza di caratteri consecutivi che non sono
delimitatori.
 * </ul><p>
 * Un oggetto della classe <tt>StringTokenizer</tt> mantiene internamente la
 * posizione corrente del cursore mobile sulla stringa da suddividere.
 * Alcune operazioni avanzano tale posizione corrente dopo i caratteri
 * processati.<p>
 * Un token è restituito prendendo una sottostringa della stringa usata per
 * costruire l'oggetto <tt>StringTokenizer</tt>.
 * <p>
 * Il segente è un esempio di utilizzo del tokenizer. Il codice:
 * <blockquote><pre>
 *     StringTokenizer st("this is a test");
 *     while (st.hasMoreTokens()) {
 *         cout << st.nextToken() << endl;
 *     }
 * </pre></blockquote>
 * <p>
 * stampa il seguente ouput:
 * <blockquote><pre>
 *     this
 *     is
 *     a
 *     test
 * </pre></blockquote>
 *
 * @author  Domenico Testa
 * @version 1.26, 24/02/03
 */
class StringTokenizer {
    int currentPosition;    // Posizione del cursore sulla stringa
    int newPosition;
    int maxPosition;        // Massimo indice
    std::string str;        // Stringa da analizzare
    std::string delimiters; // Set di delimitatori
    bool retDelims;         // Flag per il controllo sui delimitatori
    bool delimsChanged;     // Flag per la modifica dinamica dei
delimitatori
    /**
    * maxDelimChar conserva il valore del carattere delimitatore con il
valore
    * più alto. E' utilizzato per ottimizzare il riconoscimento dei
caratteri
    * delimitatori.
    */
    char maxDelimChar;
    /**
     * Imposta maxDelimChar al carattere più grande nel set dei
delimitatori.
     */
    void setMaxDelimChar();
    /**
     * Salta i delimitatori a partire dalla posizione specificata.
     * Se retDelims è false, restituisce l'indice del primo carattere non
     * delimitatore trovato (potrebbe anche essere startPos).
     * Se retDelims è true, viene sempre restituito startPos.
     */
    int skipDelimiters(const int startPos);
    /**
     * Scorre i caratteri a partire da startPos e restituisce l'indice del
     * prossimo delimitatore incontrato, oppure maxPosition se nessun
     * delimitatore viene trovato.
     */
    int scanToken(const int startPos);
  public:
    /**
     * Costruisce uno StringTokenizer per la stringa specificata.
     * Tutti i caratteri nell'argomento <code>delim</code> sono i
delimitatori
     * per separare i tokens.
     * <p>
     * Se il flag <code>returnDelims</code> è <code>true</code>, allora
     * i caratteri di delimitazione sono restituiti come tokens.
     * Ogni delimitatore è restituito come una stringa di lunghezza uno.
     * Se il flag è <code>false</code>, il carattere di delimitazione è
saltato
     * e serve solo come separatore tra tokens.
     *
     * @param   str            una stringa da analizzare.
     * @param   delim          i delimitatori
     * @param   returnDelims   flag indicante se resituire i delimitatori
     *                         come tokens.
     */
    StringTokenizer(const std::string& str, const std::string& delim = "
\t\n\r\f", bool returnDelims = false);
  public:
    /**
     * Controlla se ci sono altri token disponibili dalla stringa di questo
     * tokenizer. Se il metodo restituisce <tt>true</tt>, allora una
successiva
     * chiamata al metodo <tt>nextToken</tt> senza argomenti restituirà con
     * successo un token.
     *
     * @return  <code>true</code> se e solo se c'è almeno un token dopo la
     *          posizione corrente; altrimenti <code>false</code>.
     */
    bool hasMoreTokens();
    /**
     * Restituisce il token successivo.
     */
    std::string nextToken();
    /**
     * Restituisce il token successivo, prima il set di caratteri
delimitatori
     * di questo oggetto <tt>StringTokenizer</tt> è impostato con i
caratteri
     * contenuti nella stringa <tt>delim</tt>.
     * Dunque il token successivo nella stringa viene restituito. La
posizione
     * corrente è impostata al carattere successivo al token.
     * Il nuovo set di delimitatori rimane impostato dopo questa chiamata.
     *
     * @param   delim   i nuovi delimitatori.
     * @return  il prossimo token, dopo aver cambiato i delimitatori.
     */
    std::string nextToken(const std::string& delim);
    /**
     * Restituisce il prossimo token senza avanzare il cursore interno
     * dell'oggetto.
     * @return il prossimo token
     * @see peekNextToken(const std::string& delim) nextToken()
nextToken(const std::string& delim)
     */
    std::string peekNextToken();
     /**
     * Restituisce il prossimo token senza avanzare il cursore interno
     * dell'oggetto modificando prima il set di caratteri delimitatori.
     * di questo oggetto <tt>StringTokenizer</tt> è impostato con i
caratteri
     * contenuti nella stringa <tt>delim</tt>.
     * Dunque il token successivo nella stringa viene restituito. La
posizione
     * corrente non viene modificata in modo tale che una successiva
chiamata al
     * metodo nextToken() restituisca lo stesso token.
     * Il nuovo set di delimitatori rimane impostato dopo questa chiamata.
     *
     * @param   delim   i nuovi delimitatori.
     * @return  il prossimo token, dopo aver cambiato i delimitatori.
     * @see peekNextToken() nextToken() nextToken(const std::string& delim)
     */
    std::string peekNextToken(const std::string& delim);
    /**
     * Restituisce il numero di token non ancora elaborati da quest'oggetto
     * <code>StringTokenizer</code>.
     * @return il numero di token ancora non elaborati
     */
    int countTokens();
};
#endif // STRINGTOKENIZER_H
/*
 * @(#)StringTokenizer.cpp 15.56 24/02/03
 *
 * Implemetazione della classe StringTokenizer.
 * Liberamente tradotta e modificata a partire dai sorgenti del
 * JDK 1.4.1_02. Distribuibile secondo la licenza originale Sun.
 */
#include "StringTokenizer.h"
#include <cassert>
using namespace std;
/* Costruttore della classe */
StringTokenizer::StringTokenizer(const string& str,
                                 const string& delim = " \t\n\r\f",
                                 bool returnDelims = false) {
    currentPosition = 0;
    newPosition = -1;
    delimsChanged = false;
    this->str = str;
    maxPosition = str.length();
    delimiters = delim;
    retDelims = returnDelims;
    setMaxDelimChar();
}
/* Imposta maxDelimChar al più grande dei delimitatori */
void StringTokenizer::setMaxDelimChar() {
    if(delimiters.length() <= 0) {
        /* Non sono stati definiti dei delimitatori */
        maxDelimChar = 0;
        return;
    }
    char m = 0;
    char c;
    for(int i=0; i<delimiters.length(); i++) {
        c = 
delimiters.at
(i);
        if(m < c) m = c;
    }
    maxDelimChar = m;
}
int StringTokenizer::skipDelimiters(const int startPos) {
    // Si assicura che siano stati definiti dei delimitatori:
    assert(delimiters.length() >= 0);
    // Cursore per la ricerca:
    int position = startPos;
    // A partire da position legge carattere per carattere:
    while(!retDelims && (position < maxPosition)) {
        // Legge un carattere
        char c = 
str.at
(position);
        // Controlla se il carattere letto è un delimitatore
        if(c > maxDelimChar) {
            break;
        }
        if(delimiters.find_first_of(c) < 0) {
            break;
        }
        position++;
    }
    return position;
}
int StringTokenizer::scanToken(const int startPos) {
    int position = startPos;
    // A partire da position legge carattere per carattere:
    while (position < maxPosition) {
        char c = 
str.at
(position);
        // Controlla che il carattere sia un delimitatore
        int _pos;
        if (c <= maxDelimChar) {
            if((_pos = delimiters.find_first_of(c)) >= 0) {
                break;
            }
        }
        position++;
    }
    if (retDelims && (startPos == position)) {
        char c = 
str.at
(position);
        if ((c <= maxDelimChar) && (delimiters.find_first_of(c) >= 0))
            position++;
    }
    return position;
}
bool StringTokenizer::hasMoreTokens() {
    newPosition = skipDelimiters(currentPosition);
    return (newPosition < maxPosition);
}
string StringTokenizer::nextToken() {
    currentPosition = (newPosition >= 0 && !delimsChanged) ?
                      newPosition :
                      skipDelimiters(currentPosition);
    /* Li resetta comunque */
    delimsChanged = false;
    newPosition = -1;
    assert(currentPosition < maxPosition);
    int start = currentPosition;
    currentPosition = scanToken(currentPosition);
    return str.substr(start, currentPosition - start);
}
string StringTokenizer::nextToken(const string& delim) {
    delimiters = delim;
    delimsChanged = true;
    setMaxDelimChar();
    return nextToken();
}
string StringTokenizer::peekNextToken() {
    currentPosition = (newPosition >= 0 && !delimsChanged) ?
                      newPosition :
                      skipDelimiters(currentPosition);
    /* Li resetta comunque */
    delimsChanged = false;
    newPosition = -1;
    assert(currentPosition < maxPosition);
    int start = currentPosition;
    int end = scanToken(currentPosition);
    return str.substr(start, end - start);
}
string StringTokenizer::peekNextToken(const string& delim) {
    delimiters = delim;
    delimsChanged = true;
    setMaxDelimChar();
    return peekNextToken();
}
int StringTokenizer::countTokens() {
    int count = 0;
    int currpos = currentPosition;
    while(currpos < maxPosition) {
        currpos = skipDelimiters(currpos);
        if(currpos >= maxPosition) break;
        currpos = scanToken(currpos);
        count++;
    }
    return count;
}