#c #string-formatting #iostream
#c #форматирование строки #iostream
Вопрос:
Я ищу что-то, где:
string pearString ("pear");
string bananaString ("banana");
cout << ???? 5 ??? pearString ??????? << "[end]" << endl;
cout << ???? 5 ??? bananaString ??????? << "[end]" << endl;
Будет (для некоторой последовательности символов кода ???) вывод:
pear[end]
banan[end]
Но я бы хотел, чтобы это работало без необходимости выполнять операцию подстроки, которая копировала бы строку. Если я чего-то не упустил, для этого нет спецификатора форматирования. (Спецификатор setw заполняет более короткие строки, но позволяет переполнять более длинные.)
«Хитрой» вещью, о которой я подумал, было бы создать облегченный класс-оболочку с собственным оператором вывода потока. Для этого потребуется (неконстантная) ссылка на строку и ограничение в ее конструкции. Затем оператор вывода проверит длину, выполнит стандартный вывод, если он меньше или равен пределу. Если бы оно было больше, оно бы временно вставило нулевой символ в позицию длины, достаточную для выполнения вывода … а затем вернуло исходный символ обратно.
(ОБНОВЛЕНИЕ: на самом деле эта идея не сработала бы, поскольку <<
игнорирует встроенные нули.)
В любом случае идея того, как это будет выглядеть, будет:
cout << strlimiter(5, pearString) << "[end]" << endl;
cout << strlimiter(5, bananaString) << "[end]" << endl;
Какие-нибудь более чистые решения, которые работали бы с постоянными строками и не выводили бы данные из-под вас? Что-то, что использует другие перехваты или приемы расширения iostream? Это где-то покрыто библиотекой?
ОБНОВЛЕНИЕ: я упустил из виду write
метод iostream вместо <<
, так что вот несколько примеров кода:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class strlimiter
{
friend ostreamamp; operator<< (ostreamamp; os, strlimiter sl);
private:
const stringamp; data;
size_t limit;
public:
strlimiter(const stringamp; data, size_t limit) : data(data), limit(limit) {}
~strlimiter() {}
};
ostreamamp; operator<< (ostreamamp; os, strlimiter sl) {
return os.write(sl.data.c_str(), min(sl.data.length(), sl.limit));
}
int main() {
string pearString ("pear");
string bananaString ("banana");
cout << strlimiter(pearString, 5) << "[end]" << endl;
cout << strlimiter(bananaString, 5) << "[end]" << endl;
return 0;
}
Еще какие-нибудь хитрости, которые могли бы снизить затраты во время выполнения?
Ответ №1:
Почему бы просто не использовать write
функцию-член ostream
:
cout.write(bananaString.c_str(),5);
Возможно, удивительно, что вы даже можете поместить это в начало цепочки вставки. Взяв за основу ваш пример, вы можете использовать следующую несколько запутанную цепочку:
cout.write(bananaString.c_str(),5) << "[end]" << endl;
Комментарии:
1. Использование write — это определенно то, о чем я должен был подумать,
<<
по какой-то причине я застрял. Однако метод write игнорирует встроенные нули и фактически помещает указанное вами количество байтов в поток. Таким образом, его нельзя использовать для прямого решения этой проблемы без какой-либо упаковки для проверки длины…2. @HostileFork: operator<< для std::string также игнорирует встроенные нули. Если вам нужно другое поведение, то лучше всего проверить длину перед раздачей. Я сомневаюсь, что вы можете добиться большей эффективности.
3. Правильно, просто говорю, что я не могу просто использовать вашу вторую строку
cout.write(bananaString.c_str(),limit)
в общем случае попытки печати до предела…
Ответ №2:
Для вашего класса-оболочки в перегруженном operator<<
, вместо использования <<
в строке, используйте ostream::write
функцию.
the_stream.write(the_string.c_str(), the_size);
Комментарии:
1. D’oh. Ага. Спасибо. Добавлен некоторый код, не стесняйтесь добавлять любые другие замечания или идеи по улучшению…