J'ai redirigé "cin" pour lire à partir d'un flux de fichiers cin.rdbug(inF.rdbug())
Lorsque j'utilise l'opérateur d'extraction, il lit jusqu'à ce qu'il atteigne un caractère d'espace blanc.
Est-il possible d'utiliser un autre délimiteur? J'ai parcouru l'API sur cplusplus.com, mais je n'ai rien trouvé.
Il est possible de changer le délimiteur inter-Word pour cin
ou tout autre std::istream
, en utilisant std::ios_base::imbue
pour ajouter un --- ctype
facet
personnalisé.
Si vous lisez un fichier dans le style de/etc/passwd, le programme suivant lira chaque :
- Word délimité séparément.
#include <locale>
#include <iostream>
struct colon_is_space : std::ctype<char> {
colon_is_space() : std::ctype<char>(get_table()) {}
static mask const* get_table()
{
static mask rc[table_size];
rc[':'] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
return &rc[0];
}
};
int main() {
using std::string;
using std::cin;
using std::locale;
cin.imbue(locale(cin.getloc(), new colon_is_space));
string Word;
while(cin >> Word) {
std::cout << Word << "\n";
}
}
Pour les chaînes, vous pouvez utiliser std::getline
surcharges à lire à l'aide d'un délimiteur différent.
Pour l'extraction de nombres, le délimiteur n'est pas vraiment un "espace" pour commencer, mais tout caractère invalide dans un nombre.
Il s'agit d'une amélioration par rapport à la réponse de Robᵩ , car c'est la bonne (et je suis déçu qu'elle n'ait pas été acceptée.)
Ce que vous devez faire est de modifier le tableau que ctype
examine pour décider ce qu'est un délimiteur.
Dans le cas le plus simple, vous pouvez créer le vôtre:
const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};
Sur ma machine '\n'
est 10. J'ai défini cet élément du tableau sur la valeur du délimiteur: ctype_base::space
. Un ctype
initialisé avec foo
ne délimiterait que sur '\n'
ne pas ' '
ou '\t'
.
Maintenant, c'est un problème parce que le tableau passé dans ctype
définit plus que ce qu'est un délimiteur, il définit également des lettres, des nombres, des symboles et d'autres ordures nécessaires pour la diffusion en continu. ( Ben Voigt la réponse touche à ce sujet.) Donc ce que nous voulons vraiment faire est modifier un mask
, pas en créer un à partir de zéro.
Cela peut être accompli comme ceci:
const auto temp = ctype<char>::classic_table();
vector<ctype<char>::mask> bar(temp, temp + ctype<char>::table_size);
bar[' '] ^= ctype_base::space;
bar['\t'] &= ~(ctype_base::space | ctype_base::cntrl);
bar[':'] |= ctype_base::space;
Un ctype
initialisé avec bar
délimiterait sur '\n'
et ':'
mais non ' '
ou '\t'
.
Vous allez configurer cin
, ou tout autre istream
, pour utiliser votre ctype
personnalisé comme ceci:
cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));
Vous pouvez également basculer entre ctype
s et le comportement changera en cours de route:
cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));
Si vous devez revenir au comportement par défaut, procédez comme suit:
cin.imbue(locale(cin.getloc(), new ctype<char>));
Il s'agit d'une amélioration de la réponse de Jon et de l'exemple de cppreference.com . Cela suit donc la même prémisse que les deux, mais les combine avec des délimiteurs paramétrés.
struct delimiter_ctype : std::ctype<char> {
static const mask* make_table(std::string delims)
{
// make a copy of the "C" locale table
static std::vector<mask> v(classic_table(), classic_table() + table_size);
for(mask m : v){
m &= ~space;
}
for(char d : delims){
v[d] |= space;
}
return &v[0];
}
delimiter_ctype(std::string delims, ::size_t refs = 0) : ctype(make_table(delims), false, refs) {}
};
À votre santé!