Подтвердить что ты не робот

Изменение разделителя для cin (С++)

Я перенаправил "cin" для чтения из потока файлов cin.rdbug(inF.rdbug()) Когда я использую оператор извлечения, он читает, пока не достигнет символа пробела.

Можно ли использовать другой разделитель? Я прошел через api в cplusplus.com, но ничего не нашел.

4b9b3361

Ответ 1

Можно изменить разделитель между словами cin или любой другой std::istream, используя std::ios_base::imbue, чтобы добавить пользовательский ctype facet.

Если вы читаете файл в стиле /etc/passwd, следующая программа будет читать каждое : -delimited word отдельно.

#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";
  }
}

Ответ 2

Для строк вы можете использовать перегрузки std::getline для чтения с использованием другого разделителя.

Для извлечения номера разделитель на самом деле не является "белым", но любой символ недействителен в числе.

Ответ 3

Это улучшение в ответе Robᵩ, потому что это правильный (и я разочарован тем, что он не был принят.)

Что вам нужно сделать, это изменить массив, который ctype определяет, что такое разделитель.

В простейшем случае вы можете создать свой собственный:

const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};

На моей машине '\n' равно 10. Я установил этот элемент массива в значение разделителя: ctype_base::space. A ctype, инициализированный с помощью foo, будет ограничивать только '\n' не ' ' или '\t'.

Теперь это проблема, потому что массив, переданный в ctype, определяет больше, чем просто разделитель, он также определяет символы, цифры, символы и некоторые другие нежелательные файлы, необходимые для потоковой передачи. (ответ Ben Voigt касается этого.) Так что мы действительно хотим сделать, это изменить mask, а не создавать его с нуля.

Это можно сделать следующим образом:

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;

A ctype, инициализированный с помощью bar, будет делиться на '\n' и ':', но не ' ' или '\t'.

Вы собираетесь настроить cin или любой другой istream, чтобы использовать свой собственный ctype следующим образом:

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

Вы также можете переключаться между ctype, и поведение изменит средний поток:

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

Если вам нужно вернуться к поведению по умолчанию, просто выполните следующее:

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

[Пример в реальном времени]