Изменение разделителя для cin (С++)
Я перенаправил "cin" для чтения из потока файлов cin.rdbug(inF.rdbug())
Когда я использую оператор извлечения, он читает, пока не достигнет символа пробела.
Можно ли использовать другой разделитель? Я прошел через api в cplusplus.com, но ничего не нашел.
Ответы
Ответ 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>));
[Пример в реальном времени]