changer le délimiteur pour cin (c++)

j'ai redirigé "cin" pour lire à partir d'un flux de fichiers cin.rdbug(inF.rdbug()) Lorsque j'utilise l'extraction de l'opérateur, il lit jusqu'à ce qu'il atteigne un caractère espace blanc.

Est-il possible d'utiliser un autre délimiteur? Je suis passé par l'api dans cplusplus.com mais je n'ai rien trouvé.

36
demandé sur Jonathan Mee 2011-09-05 04:32:42

3 réponses

il est possible de changer le délimiteur d'inter-mots pour cin ou std::istream, en utilisant std::ios_base::imbue pour ajouter un custom ctypefacet.

si vous lisez un fichier dans le style de / etc / passwd, le programme suivant Lira chacun des : - mots délimités 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";
  }
}
33
répondu Robᵩ 2013-08-28 19:19:05

Pour les chaînes, vous pouvez utiliser le std::getline surcharges à lire à l'aide d'un délimiteur différent.

pour l'extraction de nombres, le délimiteur n'est pas vraiment "whitespace" pour commencer, mais n'importe quel caractère invalide dans un nombre.

17
répondu Ben Voigt 2013-08-28 19:19:37

C'est une amélioration sur Robᵩ's réponse, parce que c'est la bonne (et je suis déçu qu'il n'a pas été acceptée.)

Ce que vous devez faire est de modifier le tableau ctype regarde pour décider ce qu'est un délimiteur.

Dans le cas le plus simple, vous pouvez créer votre propre:

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' 10. J'ai placé cet élément du tableau à la valeur du délimiteur:ctype_base::space. ctype initialisé avec foo délimiterait seulement sur '\n'' ' ou '\t'.

Maintenant, c'est un problème parce que le tableau passé en ctype définit plus que ce qu'est un délimiteur, il définit aussi les lettres, les nombres, les symboles, et d'autres cochonneries nécessaires pour le streaming. ( Ben Voigt 's la réponse touche à cela.) Donc, ce que nous voulons vraiment, c'est modifiermask, pas d'en créer un à partir de zéro.

Qui 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;

ctype initialisé avec bar délimiter sur '\n' et ':' mais pas ' ' ou '\t'.

Vous allez sur la configuration de cin, ou istream pour utiliser votre custom ctype comme ceci:

cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));

vous pouvez aussi basculer entre ctypes et le comportement de changement de milieu de jet:

cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));

si vous avez besoin de revenir au comportement par défaut, faites ceci:

cin.imbue(locale(cin.getloc(), new ctype<char>));

Live exemple

15
répondu Jonathan Mee 2018-06-21 12:26:36