Como repetir uma seqüência de caracteres um número variável de vezes em C ++?


127

Quero inserir 'n' espaços (ou qualquer string) no início de uma string em C ++. Existe alguma maneira direta de fazer isso usando std :: strings ou char * strings?

Por exemplo, em Python, você poderia simplesmente fazer

>>> "." * 5 + "lolcat"
'.....lolcat'
c++ 

Alguém forneceu uma resposta usando QString?
Akiva 12/12

Respostas:



39

Não existe uma maneira idiomática direta de repetir seqüências de caracteres em C ++ equivalentes ao operador * em Python ou ao operador x em Perl. Se você estiver repetindo um único caractere, o construtor de dois argumentos (conforme sugerido pelas respostas anteriores) funcionará bem:

std::string(5, '.')

Este é um exemplo artificial de como você pode usar um ostringstream para repetir uma string n vezes:

#include <sstream>

std::string repeat(int n) {
    std::ostringstream os;
    for(int i = 0; i < n; i++)
        os << "repeat";
    return os.str();
}

Dependendo da implementação, isso pode ser um pouco mais eficiente do que simplesmente concatenar a sequência n vezes.


17

Use uma das formas de string :: insert:

std::string str("lolcat");
str.insert(0, 5, '.');

Isto irá inserir "....." (cinco pontos) no início da string (posição 0).


15
O OP pediu para repetir uma string, não um caractere.
Brent

@Brent O OP solicitou os dois - "n 'espaços (ou qualquer string)" e depois demonstra sua intenção com um único período como a string. O inglês não é o idioma principal de muitas pessoas, portanto, às vezes, você precisa adivinhar exatamente os requisitos e, quando analisado, a pergunta é realmente como fazer isso com um único caractere. Lamento que você tenha achado minha resposta inútil o suficiente para votar.
Camh

13

Sei que essa é uma pergunta antiga, mas estava procurando fazer a mesma coisa e encontrei o que considero uma solução mais simples. Parece que o cout tem essa função integrada com o cout.fill (), veja o link para uma explicação 'completa'

http://www.java-samples.com/showtutorial.php?tutorialid=458

cout.width(11);
cout.fill('.');
cout << "lolcat" << endl;

saídas

.....lolcat

6
apenas pontos: mudança de última linha para ...cout << "" << endl;
musefan

9

Para efeitos de exemplo fornecido pelo OP std :: ctor da corda é suficiente: std::string(5, '.'). No entanto, se alguém estiver procurando por uma função para repetir std :: string várias vezes:

std::string repeat(const std::string& input, unsigned num)
{
    std::string ret;
    ret.reserve(input.size() * num);
    while (num--)
        ret += input;
    return ret;
}

8

Como o comodoro Jaeger mencionou, não acho que nenhuma das outras respostas realmente responda a essa pergunta; a pergunta pergunta como repetir uma string, não um caractere.

Embora a resposta dada pelo Commodore esteja correta, é bastante ineficiente. Aqui está uma implementação mais rápida, a idéia é minimizar as operações de cópia e as alocações de memória aumentando primeiro exponencialmente a string:

#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;
}

Também podemos definir um operator*para obter algo mais próximo da versão do Python:

#include <utility>

std::string operator*(std::string str, std::size_t n)
{
    return repeat(std::move(str), n);
}

Na minha máquina, isso é cerca de 10x mais rápido que a implementação fornecida pelo Commodore e cerca de 2x mais rápido que uma solução ingênua 'acrescentar n - 1 vezes' .


Sua implementação não 'minimiza a cópia'. Lembre-se de que o +=loop for interno também possui um loop de algum tipo que faz str.size()iterações. str.size()cresce em cada iteração do loop externo; portanto, após cada iteração externa, o loop interno precisa fazer mais iterações. Sua implementação e a ingênua 'cópia n vezes' no total dos dois n * periodcaracteres de cópia . Sua implementação faz apenas uma alocação de memória por causa da inicial reserve. Eu acho que você definiu o perfil de sua implementação com um tamanho pequeno stre grande n, mas não também com tamanho grande stre pequeno n.
Florian Kaufmann

@FlorianKaufmann Não sei por que você escolheu atacar minha resposta. Mas, por "minimizar a cópia", quero dizer 'operações de cópia'. A ideia é que copiar um pequeno número de grandes blocos é mais eficiente (por várias razões) do que copiar um grande número de pequenos blocos. Eu potencialmente evito uma alocação adicional na string de entrada sobre o método ingênuo.
Daniel

2
Foi um comentário afirmando que não acredito na sua afirmação de que sua solução é muito melhor em termos de eficiência do que a solução ingênua. Nas minhas medições, comparado com a solução ingênua, seu código é mais rápido com pequenas seqüências de caracteres e muitas repetições, mas mais lento com longas e poucas repetições. Você poderia fornecer links explicando com mais detalhes a variedade de razões pelas quais a cópia de alguns blocos grandes tem um desempenho mais alto do que a cópia de muitos blocos pequenos? Eu posso pensar na previsão do ramo. Em relação ao cache da CPU, não tenho certeza de qual variante é a preferida.
Florian Kaufmann

@FlorianKaufmann Não vejo diferença significativa entre grandes stre pequenas nentre as duas abordagens. Acredito que isso tem mais a ver com o pipeline geral do que a previsão de ramificação em si, também há questões de alinhamento de dados a serem consideradas. Você deve fazer uma nova pergunta para os detalhes de por que isso é mais compatível com o processador / memória, tenho certeza de que isso despertaria muito interesse e receberia uma resposta melhor do que posso fornecer aqui.
Daniel

1
@FlorianKaufmann: No x86, rep movsbé uma das maneiras mais eficientes de copiar, pelo menos para cópias médias e grandes. Sua implementação microcodificada possui uma sobrecarga de inicialização quase constante (tanto na AMD quanto na Intel), por exemplo, em Sandybridge, de 15 a 40 ciclos, mais 4 ciclos por linha de cache de 64B (melhor caso) . Para cópias pequenas, um loop SSE é melhor porque não possui a sobrecarga de inicialização. Mas, em seguida, está sujeito a erros de ramificação.
Peter Cordes


5

ITNOA

Você pode usar a função C ++ para fazer isso.

 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();
 }

1
O que diabos significa "ITNOA"? Não foi possível encontrar nenhuma referência on-line.
Seguindo em
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.