C ++에서 문자열을 가변 횟수로 반복하는 방법은 무엇입니까?


127

C ++에서 문자열 시작 부분에 'n'공백 (또는 임의의 문자열)을 삽입하고 싶습니다. std :: strings 또는 char * 문자열을 사용하여이를 수행하는 직접적인 방법이 있습니까?

예를 들어 Python에서는 간단히 할 수 있습니다.

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

누군가 QString을 사용하여 답변을 제공합니까?
Akiva 2015

답변:



39

Python 의 * 연산자 또는 Perl 의 x 연산자에 해당하는 C ++에서 문자열을 반복하는 직접적인 관용적 방법은 없습니다 . 단일 문자를 반복하는 경우 이전 답변에서 제안한대로 두 인수 생성자가 잘 작동합니다.

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 번 연결하는 것보다 약간 더 효율적일 수 있습니다.


17

string :: insert 형식 중 하나를 사용합니다.

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

이렇게하면 문자열 시작 (위치 0)에 "....."(점 5 개)가 삽입됩니다.


15
OP는 문자가 아닌 문자열 반복을 요청했습니다.
Brent

@Brent OP는 " 'n'공백 (또는 임의의 문자열)"을 모두 요청한 다음 문자열로 단일 마침표를 사용하여 의도를 보여줍니다. 영어는 많은 사람들의 모국어가 아니므로 정확한 요구 사항을 추측해야 할 때가 있으며 분석 할 때 질문은 실제로 단일 문자로이를 수행하는 방법을 묻는 것입니다. 내 답변이 도움이되지 않아서 반대표를 던지 셨다니 유감입니다.
camh dec

13

나는 이것이 오래된 질문이라는 것을 알고 있지만 똑같은 일을 찾고 있었고 더 간단한 해결책이라고 생각하는 것을 발견했습니다. cout에는 cout.fill ()과 함께이 함수가 내장되어있는 것 같습니다. '전체'설명은 링크를 참조하십시오.

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

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

출력

.....lolcat

6
단 점 : 변화에 대한 마지막 줄 ...cout << "" << endl;
musefan

9

OP std :: string의 ctor가 제공하는 예제의 목적을 위해 충분 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;
}

8

Commodore Jaeger가 언급했듯이, 나는 다른 답변 중 어떤 것도 실제로이 질문에 답하지 않는다고 생각합니다. 질문은 문자가 아닌 문자열을 반복하는 방법을 묻습니다.

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*파이썬 버전에 더 가까운 것을 얻기 위해를 정의 할 수도 있습니다 .

#include <utility>

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

내 컴퓨터에서 이것은 Commodore가 제공 한 구현보다 약 10 배 빠르며 순진한 'append n-1 times' 솔루션 보다 약 2 배 빠릅니다 .


구현은 '복사를 최소화'하지 않습니다. (가) 것을 마음 +=당신을위한 루프 내에서 내부적으로도 않습니다 어떤 종류의 루프가 str.size()반복. str.size()각 외부 루프 반복에서 증가하므로 각 외부 반복 후에 내부 루프가 더 많은 반복을 수행해야합니다. 당신과 순진한 '복사 n 번'구현은 총 두 복사 n * period문자입니다. 구현은 초기 reserve. 난 당신이 작은 편으로 구현을 프로파일 생각 str하고 큰 n, 그러나 또한 큰 str작은 n.
Florian Kaufmann

@FlorianKaufmann 왜 내 대답을 공격하기로 선택했는지 잘 모르겠습니다. 그러나 "최소한 복사"란 "복사 작업"을 의미합니다. 많은 수의 작은 블록을 복사하는 것보다 적은 수의 큰 블록을 복사하는 것이 (다양한 이유로) 더 효율적이라는 아이디어입니다. 순진한 방법을 통해 입력 문자열에 대한 추가 할당을 잠재적으로 피할 수 있습니다.
Daniel

2
귀하의 솔루션이 순진한 솔루션보다 효율성 측면에서 훨씬 낫다는 귀하의 주장을 믿지 않는다는 의견이었습니다. 내 측정에서 순진한 솔루션에 비해 코드는 작은 문자열과 많은 반복으로 더 빠르지 만 긴 문자열과 몇 번의 반복에서는 느립니다. 몇 개의 큰 블록을 복사하는 것이 여러 개의 작은 블록을 복사하는 것보다 더 높은 성능을 갖는 다양한 이유를 더 자세히 설명하는 링크를 제공 할 수 있습니까? 분기 예측을 생각할 수 있습니다. CPU 캐시와 관련하여 어떤 변형이 선호되는지 잘 모르겠습니다.
플로리안 카우프만

@FlorianKaufmann 나는 두 접근 방식 사이 에 크고 str작은 것에 대한 큰 차이가 없다고 생각 n합니다. 나는 이것이 분기 예측 그 자체보다 전체 파이프 라인 과 더 관련이 있다고 생각 하며 고려해야 할 데이터 정렬 문제 도 있습니다 . 이것이 프로세서 / 메모리 친화적 인 이유에 대한 세부 사항에 대해 새로운 질문을해야합니다. 많은 관심을 끌 것이며 여기에서 제공 할 수있는 것보다 더 나은 답변을받을 것입니다.
다니엘

1
@FlorianKaufmann : x86에서는 rep movsb최소한 중대형 복사본의 경우 가장 효율적인 복사 방법 중 하나입니다. 마이크로 코딩 된 구현은 (AMD와 Intel 모두에서) 거의 일정한 시작 오버 헤드 (예 : Sandybridge에서 ~ 15 ~ 40 사이클)와 64B 캐시 라인 당 4 사이클 (최상의 경우) 을 갖습니다 . 작은 복사본의 경우 시작 오버 헤드가 없기 때문에 SSE 루프가 가장 좋습니다. 그러나 그것은 분기의 잘못된 예측의 대상이됩니다.
Peter Cordes


5

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

1
도대체 "ITNOA"는 무엇을 의미합니까? 온라인에서 참조를 찾을 수 없습니다.
Folling
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.