C ++ 'da bir dizenin başına' n 'boşluk (veya herhangi bir dize) eklemek istiyorum. Std :: strings veya char * strings kullanarak bunu yapmanın doğrudan bir yolu var mı?
Örneğin Python'da şunları yapabilirsiniz:
>>> "." * 5 + "lolcat"
'.....lolcat'
C ++ 'da bir dizenin başına' n 'boşluk (veya herhangi bir dize) eklemek istiyorum. Std :: strings veya char * strings kullanarak bunu yapmanın doğrudan bir yolu var mı?
Örneğin Python'da şunları yapabilirsiniz:
>>> "." * 5 + "lolcat"
'.....lolcat'
Yanıtlar:
Tek bir karakterin tekrarlanması durumunda, şunları kullanabilirsiniz std::string(size_type count, CharT ch)
:
std::string(5, '.') + "lolcat"
NB. Bu, çok karakterli dizeleri tekrarlamak için kullanılamaz.
Python'daki * operatörüne veya Perl'deki x operatörüne eşdeğer C ++ 'da dizeleri tekrar etmenin doğrudan deyimsel bir yolu yoktur . Tek bir karakteri tekrarlıyorsanız, iki bağımsız değişkenli kurucu (önceki cevaplarda önerildiği gibi) iyi çalışır:
std::string(5, '.')
Bu, bir dizgeyi n kez yinelemek için bir ostringstream'i nasıl kullanabileceğinizin uydurma bir örneğidir:
#include <sstream>
std::string repeat(int n) {
std::ostringstream os;
for(int i = 0; i < n; i++)
os << "repeat";
return os.str();
}
Gerçekleştirmeye bağlı olarak, bu, dizeyi n kez bitiştirmekten biraz daha verimli olabilir.
String :: insert biçimlerinden birini kullanın:
std::string str("lolcat");
str.insert(0, 5, '.');
Bu, dizinin başına (konum 0) "....." (beş nokta) ekleyecektir.
Bunun eski bir soru olduğunu biliyorum, ama ben de aynı şeyi yapmak istiyordum ve daha basit bir çözüm olduğunu düşündüğüm şeyi buldum. Görünüşe göre cout, cout.fill () ile yerleşik bu işleve sahiptir, 'tam' açıklama için bağlantıya bakın
http://www.java-samples.com/showtutorial.php?tutorialid=458
cout.width(11);
cout.fill('.');
cout << "lolcat" << endl;
çıktılar
.....lolcat
cout << "" << endl;
OP tarafından sağlanan Örnek olması amacıyla std :: dize ait ctor yeterlidir: std::string(5, '.')
. Bununla birlikte, herhangi biri std :: string'i birden çok kez tekrarlayacak bir işlev arıyor ise:
std::string repeat(const std::string& input, unsigned num)
{
std::string ret;
ret.reserve(input.size() * num);
while (num--)
ret += input;
return ret;
}
Commodore Jaeger'in bahsettiği gibi, diğer yanıtların hiçbirinin bu soruyu gerçekten yanıtladığını sanmıyorum; soru bir karakterin değil bir dizenin nasıl tekrarlanacağını sorar.
Commodore'un verdiği cevap doğru olsa da oldukça verimsiz. İşte daha hızlı bir uygulama, fikir, önce dizeyi katlanarak büyüterek kopyalama işlemlerini ve bellek ayırmalarını en aza indirmektir:
#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;
}
Bir operator*
şeyi Python sürümüne yaklaştırmak için de tanımlayabiliriz :
#include <utility>
std::string operator*(std::string str, std::size_t n)
{
return repeat(std::move(str), n);
}
Benim makinemde bu, Commodore tarafından verilen uygulamadan yaklaşık 10 kat daha hızlı ve saf bir 'ekleme n - 1 kez' çözümünden yaklaşık 2 kat daha hızlı .
+=
for döngüsünün kendi içinde de str.size()
yinelemeler yapan bir tür döngüye sahip olduğunu unutmayın . str.size()
her dış döngü yinelemesinde büyür, bu nedenle her dış döngüden sonra iç döngü daha fazla yineleme yapmak zorundadır. Sizin ve saf 'n kez kopya' uygulaması, toplam her iki kopya n * period
karakterinde. Uygulamanız, başlangıç nedeniyle yalnızca bir bellek ayırma yapar reserve
. Sanırım uygulamanızı oldukça küçük str
ve büyük olarak profilini çıkardınız n
, ama aynı zamanda büyük str
ve küçük ile değil n
.
str
ve küçük n
arasında önemli bir fark görmüyorum . Bunun branş tahmininden çok genel boru hattıyla ilgisi olduğuna inanıyorum , ayrıca dikkate alınması gereken veri hizalama sorunları da var . Bunun neden daha işlemci / bellek dostu olduğuna dair ayrıntılar için yeni bir soru sormalısınız, eminim çok ilgi çekecek ve burada verebileceğimden daha iyi bir cevap alacaktır.
rep movsb
, en azından orta ila büyük kopyalar için kopyalama yapmanın en etkili yollarından biridir. Mikro kodlu uygulaması bazı sabit başlangıç ek yüküne sahiptir (hem AMD hem de Intel'de), örneğin Sandybridge'de ~ 15 ila 40 döngü, artı 64B önbellek satırı başına 4 döngü (en iyi durum) . Küçük kopyalar için, bir SSE döngüsü en iyisidir çünkü başlangıç ek yüküne sahip değildir. Ama sonra dallara yönelik yanlış tahminlere tabi.
ITNOA
Bunu yapmak için C ++ işlevini kullanabilirsiniz.
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();
}