Я хочу вставить пробелы «n» (или любую строку) в начало строки в C ++. Есть ли какой-либо прямой способ сделать это, используя строки std :: strings или char *?
Например, в Python вы можете просто сделать
>>> "." * 5 + "lolcat"
'.....lolcat'
Я хочу вставить пробелы «n» (или любую строку) в начало строки в C ++. Есть ли какой-либо прямой способ сделать это, используя строки std :: strings или char *?
Например, в Python вы можете просто сделать
>>> "." * 5 + "lolcat"
'.....lolcat'
Ответы:
В частном случае повторения одного символа вы можете использовать std::string(size_type count, CharT ch):
std::string(5, '.') + "lolcat"
NB. Это не может использоваться для повторения многосимвольных строк.
Нет прямого идиоматического способа повторения строк в C ++, эквивалентного оператору * в Python или оператору x в Perl. Если вы повторяете один символ, конструктор с двумя аргументами (как было предложено в предыдущих ответах) работает хорошо:
std::string(5, '.')
Это надуманный пример того, как вы можете использовать ostringstream для повторения строки n раз:
#include <sstream>
std::string repeat(int n) {
std::ostringstream os;
for(int i = 0; i < n; i++)
os << "repeat";
return os.str();
}
В зависимости от реализации это может быть немного эффективнее простого конкатенации строки n раз.
Используйте одну из форм string :: insert:
std::string str("lolcat");
str.insert(0, 5, '.');
Это вставит "....." (пять точек) в начало строки (позиция 0).
Я знаю, что это старый вопрос, но я хотел сделать то же самое и нашел то, что, по моему мнению, является более простым решением. Похоже, что cout имеет эту функцию, встроенную в cout.fill (), см. Ссылку для «полного» объяснения.
http://www.java-samples.com/showtutorial.php?tutorialid=458
cout.width(11);
cout.fill('.');
cout << "lolcat" << endl;
выходы
.....lolcat
cout << "" << endl;
Для целей примера , приведенного в OP STD :: т е р струны достаточно: std::string(5, '.'). Однако, если кто-то ищет функцию для многократного повторения std :: string:
std::string repeat(const std::string& input, unsigned num)
{
std::string ret;
ret.reserve(input.size() * num);
while (num--)
ret += input;
return ret;
}
Как намекал коммодор Джагер, я не думаю, что какие-либо другие ответы действительно отвечают на этот вопрос; вопрос спрашивает, как повторить строку, а не символ.
Хотя ответ, данный Commodore, правильный, он довольно неэффективен. Вот более быстрая реализация, идея состоит в том, чтобы минимизировать операции копирования и выделения памяти, сначала экспоненциально увеличивая строку:
#include <string>
#include <cstddef>
std::string repeat(std::string str, const std::size_t n)
{
if (n == 0) {
str.clear();
str.shrink_to_fit();
return str;
} else if (n == 1 || str.empty()) {
return str;
}
const auto period = str.size();
if (period == 1) {
str.append(n - 1, str.front());
return str;
}
str.reserve(period * n);
std::size_t m {2};
for (; m < n; m *= 2) str += str;
str.append(str.c_str(), (n - (m / 2)) * period);
return str;
}
Мы также можем определить, operator*чтобы приблизиться к версии Python:
#include <utility>
std::string operator*(std::string str, std::size_t n)
{
return repeat(std::move(str), n);
}
На моей машине это примерно в 10 раз быстрее, чем реализация, предоставленная Commodore, и примерно в 2 раза быстрее, чем наивное решение «добавить n - 1 раз» .
+=внутри вашего цикла for также есть какой-то цикл, который выполняет str.size()итерации. str.size()растет на каждой итерации внешнего цикла, поэтому после каждой внешней итерации внутренний цикл должен делать больше итераций. Ваша и наивная реализация «копировать n раз» в сумме оба копируют n * periodсимволы. Ваша реализация делает только одно выделение памяти из-за начального reserve. Я предполагаю, что вы профилировали свою реализацию с помощью довольно маленького strи большого n, но не одновременно с большим strи маленьким n.
strи малого n. Я считаю, что это больше связано с общим конвейером, чем с прогнозированием ветвления как таковым, есть также проблемы с выравниванием данных, которые следует учитывать. Вы должны задать новый вопрос о том, почему это более дружественно к процессору / памяти, я уверен, что это вызовет большой интерес и получит лучший ответ, чем я могу дать здесь.
rep movsbэто один из наиболее эффективных способов копирования, по крайней мере, для средних и больших копий. Его микрокодированная реализация имеет некоторые почти постоянные накладные расходы на запуск (как на AMD, так и на Intel), например, на Sandybridge, от ~ 15 до 40 циклов, плюс 4 цикла на строку кэша размером 64 ББ (лучший случай) . Для небольших копий лучше всего подходит цикл SSE, поскольку он не требует дополнительных затрат на запуск. Но тогда это может быть ошибочным предсказанием ветвей.
ITNOA
Для этого вы можете использовать функцию C ++.
std::string repeat(const std::string& input, size_t num)
{
std::ostringstream os;
std::fill_n(std::ostream_iterator<std::string>(os), num, input);
return os.str();
}