문자열에서 모든 문자를 바꾸는 방법?


답변:


742

std::string이러한 기능을 포함하지 않지만 헤더 replace에서 독립형 기능을 사용할 수 있습니다 algorithm.

#include <algorithm>
#include <string>

void some_func() {
  std::string s = "example string";
  std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}

6
std::string이다 컨테이너 특히 문자 시퀀스와 함께 작동하도록 설계되었습니다. 링크
Kirill V. Lyadvinsky

164
불행히도 이것은 하나의 문자 만 다른 문자로 대체 할 수 있습니다. 문자를 더 많은 문자 (즉, 문자열)로 바꿀 수 없습니다. 더 많은 문자로 검색 바꾸기를 수행하는 방법이 있습니까?
SasQ

6
@Kirill V. Lyadvinsky What 어쩌면 그냥 발생을 제거하고 싶습니다.
SIFE

4
@ KirillV.Lyadvinsky :이 방법을 사용하여 모든 x를 y로 바꾸면 결과는 원래 문자열이 무엇이든 긴 y 문자열입니다. 문제가 무엇이라고 생각하십니까? (코드는 당신이 쓴 것과 정확히 동일합니다)
Transcendent

6
@ 초월자 : 이것은 정확하게 std::string::replace()대신에 일어나는 일 입니다 std::replace()! 'x'( char)는 암시 적으로 size_t[값 120]으로 캐스트 되므로 전체 문자열 또는 그 일부가 120 개의 'y'사본으로 채워집니다.
IBue

127

나는 또한 부스트 솔루션 을 던질 것이라고 생각했다 .

#include <boost/algorithm/string/replace.hpp>

// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");

// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");

그런 다음 -I시스템에서 Boost 라이브러리를 찾기 위해 컴파일러에 대한 몇 가지 플래그 가 누락되었습니다 . 아마도 먼저 설치해야 할 수도 있습니다.
Martin Ueding

위의 내용은 std lib로 나오기 때문에 더 효과적입니다. 부스트 라이브러리를 사용하는 사람은 없습니다. ;-)
hfrmobile

122

이 문제는 character대체에 중점을두고 있지만이 페이지가 특히 유용하다는 것을 알았을 때 (특히 Konrad 의 발언) 이보다 일반적인 구현을 공유하고 싶습니다 substrings.

std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

용법:

std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;

출력 :

Number_Of_Beans

XXjXugtXty

hhjhugthty


편집하다:

위의 내용은 아무것도 반환하지 않고 ( void) 를 반환 str하고 인수로 주어진 문자열에서 직접 변경을 수행하여 value 대신 주소로 전달 함으로써 성능이 문제가되는 경우보다 적합한 방식으로 구현할 수 있습니다 . 이렇게하면 결과를 반환하는 동안 쓸모없고 비용이 많이 드는 원래 문자열의 사본을 피할 수 있습니다. 당신의 전화는 ...

코드 :

static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
    // Same inner code...
    // No return statement
}

이것이 다른 사람들에게 도움이되기를 바랍니다 ...


4
소스 문자열이 크고 대체 할 문자열이 많은 경우 성능 문제가 있습니다. string :: replace ()가 여러 번 호출되어 많은 문자열 사본이 발생합니다. 그 문제를 해결하는 내 솔루션을 참조하십시오.
minastaros

1
미리 선택 : 주소로 => 참조로 . 주소인지 아닌지는 구현 세부 사항입니다.
Max Truxa

1
실제로 from문자열이 비어 있는지 확인해야 합니다. 그렇지 않으면 무한 루프가 발생합니다.
초보자

34

전송 프로토콜이 \ 0 바이트를 허용하지 않기 때문에 모든 0x00 바이트가 "\ 1 \ x30"으로 대체되고 모든 0x01 바이트가 "\ 1 \ x31"로 대체되는 큰 이진 블로 브를 상상해보십시오.

다음과 같은 경우 :

  • 교체 할 문자열과 교체 할 문자열의 길이가 서로 다릅니다.
  • 소스 문자열 내에서 대체 될 문자열이 많이 발생합니다.
  • 소스 문자열이 큽니다.

제공된 솔루션을 적용 할 수 없거나 (단일 문자 만 대체하므로) 성능 문제가 있습니다. string :: replace를 여러 번 호출하여 얼룩 크기의 사본을 반복해서 생성하기 때문입니다. (나는 부스트 솔루션을 모른다. 아마도 그 관점에서 괜찮을 것이다)

이것은 하나의 소스 문자열의 모든 발생을 따라 산책하고 조각하여 새로운 문자열 조각 빌드 번을 :

void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
    std::string newString;
    newString.reserve(source.length());  // avoids a few memory allocations

    std::string::size_type lastPos = 0;
    std::string::size_type findPos;

    while(std::string::npos != (findPos = source.find(from, lastPos)))
    {
        newString.append(source, lastPos, findPos - lastPos);
        newString += to;
        lastPos = findPos + from.length();
    }

    // Care for the rest after last occurrence
    newString += source.substr(lastPos);

    source.swap(newString);
}

이것은 지금까지 STL에만 구축 된 최상의 솔루션입니다. 어디에서나 쉽게 사용할 수 있도록 사용자 정의 기능을 사용하려면이 기능을 사용하십시오.
로저 샌더스

21

단일 문자에 대한 간단한 찾기 및 바꾸기는 다음과 같습니다.

s.replace(s.find("x"), 1, "y")

전체 문자열에 대해이 작업을 수행하려면 s.find시작 하기 전까지 반복하는 것이 가장 쉽습니다 npos. range_error루프를 끝내기 위해 잡을 수도 있다고 생각 하지만 그게 좀 추악합니다.


7
대체 할 문자 수가 문자열 길이에 비해 적을 때 적합한 솔루션 일 수 있지만 확장 성이 떨어집니다. 원래 문자열에서 교체해야하는 문자의 비율이 증가함에 따라이 방법은 O (N ^ 2)에 접근합니다.
그리고

7
진실. 저의 일반적인 철학은 비 효율성이 실제 문제를 야기 할 때까지 쉬운 (쓰기와 읽기) 일을하는 것입니다. O (N ** 2)가 문제가되는 허밍스런 현이있을 수도 있지만 내 현이 1K 이하인 시간의 99 %가 있습니다.
TED

3
... 키릴의 방법이 더 좋았습니다 (이미 투표했습니다).
TED

"x"를 찾지 못하면 어떻게됩니까? 또한 이중 괄호를 사용하는 이유는 무엇입니까?
Prasath Govind

@PrasathGovind-방금 필요한 통화를 표시했습니다 (따라서 "같은 것"). 적절한 오류 처리와 같은 중요하지만 모호한 세부 사항은 독자의 연습으로 남았습니다. "이중 괄호"에 관해서는, 그것이 무엇인지 또는 당신이 무엇을 말하는지 잘 모르겠습니다. 나를 위해 "중괄호"는 {캐릭터입니다. 나는 "이중 버팀대"가 무엇인지 모른다. 글꼴 문제가 있습니까?
TED

6

둘 이상의 문자 std::string를 바꾸고을 다루는 경우이 조각은 sHaystack의 sNeedle을 sReplace로 바꾸고 sNeedle과 sReplace는 같은 크기 일 필요는 없습니다. 이 루틴은 왼쪽에서 오른쪽으로 발견 된 첫 번째 항목이 아니라 while 루프를 사용하여 모든 항목을 대체합니다.

while(sHaystack.find(sNeedle) != std::string::npos) {
  sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}

이것은 O (n ^)입니다. O (n) 시간 안에 할 수 있습니다.
Changming Sun

3
@ChangmingSun 어떤 O (n) 솔루션을 의미합니까?
habakuk

2
kNeedle이 sReplace의 하위 문자열 인 경우 무한 루프됩니다.
자존심

또한 find두 번 전화가 있습니다. 그 결과를 임시 변수로 만드는 것을 고려하십시오.
Luc Bloom

4

Kirill이 제안했듯이 replace 메소드를 사용하거나 각 문자를 독립적으로 바꾸는 문자열을 따라 반복하십시오.

또는 방법을 사용 find하거나 find_first_of수행해야 할 작업에 따라 사용할 수 있습니다 . 이러한 솔루션 중 어느 것도 한 번에 작업을 수행하지는 않지만 몇 줄의 추가 코드를 사용하면 효과를 발휘할 수 있습니다. :-)


3
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
    int len, loop=0;
    string nword="", let;
    len=word.length();
    len--;
    while(loop<=len){
        let=word.substr(loop, 1);
        if(let==target){
            nword=nword+replacement;
        }else{
            nword=nword+let;
        }
        loop++;
    }
    return nword;

}
//Main..
int main() {
  string word;
  cout<<"Enter Word: ";
  cin>>word;
  cout<<replace(word, "x", "y")<<endl;
  return 0;
}

word긴 경우 함수를 호출하는 동안 많은 오버 헤드가있을 수 있습니다. 당신은 전달하여이를 최적화 할 수 있습니다 word, target그리고 replacementconst를-참조한다.
TrebledJ

2

Abseil StrReplaceAll어떻습니까 ? 헤더 파일에서 :

// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
//                                                {"&", "&amp;"},
//                                                {"<", "&lt;"},
//                                                {">", "&gt;"},
//                                                {"\"", "&quot;"},
//                                                {"'", "&#39;"}});

1

오래된 학교 :-)

std::string str = "H:/recursos/audio/youtube/libre/falta/"; 

for (int i = 0; i < str.size(); i++) {
    if (str[i] == '/') {
        str[i] = '\\';
    }
}

std::cout << str;

결과:

H : \ recursos \ audio \ youtube \ libre \ falta \


0

작동합니다! 인벤토리가 .dat 파일과 같은 CSV로 저장된 서점 앱에 이와 비슷한 것을 사용했습니다. 그러나 단일 문자 인 경우 대체자가 단일 문자 일뿐입니다 (예 : '|'), 큰 따옴표 "|"여야합니다. 유효하지 않은 변환 const char을 발생시키지 않습니다.

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int count = 0;  // for the number of occurences.
    // final hold variable of corrected word up to the npos=j
    string holdWord = "";
    // a temp var in order to replace 0 to new npos
    string holdTemp = "";
    // a csv for a an entry in a book store
    string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";

    // j = npos
    for (int j = 0; j < holdLetter.length(); j++) {

        if (holdLetter[j] == ',') {

            if ( count == 0 ) 
            {           
                holdWord = holdLetter.replace(j, 1, " | ");      
            }
            else {

                string holdTemp1 = holdLetter.replace(j, 1, " | ");

                // since replacement is three positions in length,
                // must replace new replacement's 0 to npos-3, with
                // the 0 to npos - 3 of the old replacement 
                holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3); 

                holdWord = "";

                holdWord = holdTemp;

            }
            holdTemp = "";
            count++;
        }
    } 
    cout << holdWord << endl;
    return 0;
}

// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85

일반적으로 CentOS를 사용하고 있으므로 컴파일러 버전이 아래에 있습니다. C ++ 버전 (g ++), C ++ 98 기본값 :

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

0

std::strings를 기꺼이 사용하려는 경우이 샘플 앱의 strsub기능을있는 그대로 사용하거나, 거의 동일한 목표를 달성하기 위해 다른 유형 또는 매개 변수 세트를 사용하려는 경우이를 업데이트 할 수 있습니다. 기본적으로 속성 및 기능을 사용하여 std::string일치하는 문자 세트를 빠르게 지우고 원하는 문자를에 직접 삽입합니다 std::string. 이 교체 작업을 수행 할 때마다 오프셋은 교체 할 일치하는 문자를 여전히 찾을 수 있으면 업데이트되며, 더 이상 교체 할 것이 없으면 마지막 업데이트부터 상태로 문자열을 반환합니다.

#include <iostream>
#include <string>

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "yyy", "i");
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos, "ii", "y");

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(std::string stringToModify,
                   std::string charsToReplace,
                   std::string replacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, charsToReplace.size());
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
                                           this_occurrence + replacementChars.size());
    }

    return this_string;
}

std::strings를 매개 변수로 사용하지 않고 C 스타일 문자열을 대신 전달하려면 아래에서 업데이트 된 샘플을 볼 수 있습니다.

#include <iostream>
#include <string>

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars);

int main()
{
    std::string silly_typos = "annoiiyyyng syyyllii tiipos.";

    std::cout << "Look at these " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "yyy", "i", 3, 1);
    std::cout << "After a little elbow-grease, a few less " << silly_typos << std::endl;
    silly_typos = strsub(silly_typos.c_str(), "ii", "y", 2, 1);

    std::cout << "There, no more " << silly_typos << std::endl;
    return 0;
}

std::string strsub(const char * stringToModify,
                   const char * charsToReplace,
                   const char * replacementChars,
                   uint64_t sizeOfCharsToReplace,
                   uint64_t sizeOfReplacementChars)
{
    std::string this_string = stringToModify;

    std::size_t this_occurrence = this_string.find(charsToReplace);
    while (this_occurrence != std::string::npos)
    {
        this_string.erase(this_occurrence, sizeOfCharsToReplace);
        this_string.insert(this_occurrence, replacementChars);
        this_occurrence = this_string.find(charsToReplace,
            this_occurrence + sizeOfReplacementChars);
    }

    return this_string;
}

0

간단한 상황에서는 다른 라이브러리를 사용하지 않고 std :: string (이미 사용 중임)없이 잘 작동합니다.

문자의 모든 발행 수 교체 문자와 Bsome_string를 :

for (size_t i = 0; i < some_string.size(); ++i) {
    if (some_string[i] == 'a') {
        some_string.replace(i, 1, "b");
    }
}

문자열이 크거나 여러 번의 교체 호출이 문제인 경우이 답변에 언급 된 기술을 적용 할 수 있습니다. https://stackoverflow.com/a/29752943/3622300


0

여기에 최대 DRI 정신으로 구현 한 솔루션이 있습니다. sHaystack에서 sNeedle을 검색하여 sReplace로 대체합니다. 0이 아닌 경우 nTimes, 그렇지 않으면 모든 sNeedle이 발생합니다. 대체 된 텍스트에서 다시 검색하지 않습니다.

std::string str_replace(
    std::string sHaystack, std::string sNeedle, std::string sReplace, 
    size_t nTimes=0)
{
    size_t found = 0, pos = 0, c = 0;
    size_t len = sNeedle.size();
    size_t replen = sReplace.size();
    std::string input(sHaystack);

    do {
        found = input.find(sNeedle, pos);
        if (found == std::string::npos) {
            break;
        }
        input.replace(found, len, sReplace);
        pos = found + replen;
        ++c;
    } while(!nTimes || c < nTimes);

    return input;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.