Я хочу вставити пробіли 'n' (або будь-яку рядок) на початку рядка в C ++. Чи є прямий спосіб це зробити, використовуючи std :: strings або char * string?
Наприклад, у Python ви могли просто зробити
>>> "." * 5 + "lolcat"
'.....lolcat'
Я хочу вставити пробіли 'n' (або будь-яку рядок) на початку рядка в C ++. Чи є прямий спосіб це зробити, використовуючи std :: strings або char * string?
Наприклад, у 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 разів.
Використовуйте одну з форм рядка :: 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;
}
Як наголошував Комодор Йегер, я не думаю, що жодна з інших відповідей насправді не відповідає на це запитання; питання задає питання, як повторити рядок, а не символ.
Хоча відповідь Комодора правильна, вона досить неефективна. Ось більш швидка реалізація, ідея полягає в тому, щоб мінімізувати операції копіювання та розподілу пам'яті, спочатку експоненціально зростаючи рядок:
#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 раз" .
+=
внутрішній цикл для вашого циклу також має певний цикл, який робить str.size()
ітерації. str.size()
зростає в кожній ітерації зовнішньої петлі, тому після кожної зовнішньої ітерації внутрішня петля повинна робити більше ітерацій. Ваша та наївна реалізація "копіювати n разів" загалом як n * period
символи копії . Ваша реалізація здійснює лише один розподіл пам'яті через початкове reserve
. Я думаю, ви профілювали свою реалізацію досить малим str
і великим n
, але не також великим str
і малим n
.
str
та малими n
між двома підходами. Я вважаю, що це більше стосується загального конвеєрним проектом, ніж передбачення галузей, але також слід врахувати питання вирівнювання даних . Вам слід задати нове запитання, щоб дізнатись, чому це більш зручно для процесора / пам'яті, я впевнений, що він би зацікавив і отримав кращу відповідь, ніж я можу дати тут.
rep movsb
це один із найефективніших способів копіювання, принаймні для середніх та великих копій. Її мікрокодована реалізація має деякий майже постійний накладний запуск (як для AMD, так і для Intel), наприклад, на Sandybridge, від 15 до 40 циклів, плюс 4 цикли на 64B кеш-лінії (найкращий випадок) . Для невеликих копій цикл SSE найкращий, оскільки він не має накладних витрат. Але тоді це підлягає неправильним прогнозам.
ІТНОА
Для цього можна використовувати функцію 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();
}