문자열의 단어를 어떻게 반복합니까? 다음과 같습니다. #include <iostream> #include

문자열의 단어를 반복하려고합니다.

문자열은 공백으로 구분 된 단어로 구성되어 있다고 가정 할 수 있습니다.

C 문자열 함수 나 그런 종류의 문자 조작 / 액세스에는 관심이 없습니다. 또한 답변의 효율성보다 우아함을 우선시하십시오.

내가 지금 가지고있는 가장 좋은 해결책은 다음과 같습니다.

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
    string s = "Somewhere down the road";
    istringstream iss(s);

    do
    {
        string subs;
        iss >> subs;
        cout << "Substring: " << subs << endl;
    } while (iss);
}

더 우아한 방법이 있습니까?



답변

가치있는 것을 위해 표준 라이브러리 기능에만 의존하여 입력 문자열에서 토큰을 추출하는 또 다른 방법이 있습니다. STL 디자인의 힘과 우아함의 예입니다.

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>

int main() {
    using namespace std;
    string sentence = "And I feel fine...";
    istringstream iss(sentence);
    copy(istream_iterator<string>(iss),
         istream_iterator<string>(),
         ostream_iterator<string>(cout, "\n"));
}

추출 된 토큰을 출력 스트림에 복사하는 대신 동일한 일반 copy알고리즘을 사용하여 컨테이너에 삽입 할 수 있습니다 .

vector<string> tokens;
copy(istream_iterator<string>(iss),
     istream_iterator<string>(),
     back_inserter(tokens));

… 또는 vector직접 작성하십시오 .

vector<string> tokens{istream_iterator<string>{iss},
                      istream_iterator<string>{}};


답변

이것을 사용하여 문자열을 구분 기호로 나눕니다. 첫 번째는 결과를 미리 구성된 벡터에 넣고 두 번째는 새 벡터를 반환합니다.

#include <string>
#include <sstream>
#include <vector>
#include <iterator>

template <typename Out>
void split(const std::string &s, char delim, Out result) {
    std::istringstream iss(s);
    std::string item;
    while (std::getline(iss, item, delim)) {
        *result++ = item;
    }
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, std::back_inserter(elems));
    return elems;
}

이 솔루션은 빈 토큰을 건너 뛰지 않으므로 다음은 4 개의 항목을 찾게되며 그 중 하나는 비어 있습니다.

std::vector<std::string> x = split("one:two::three", ':');


답변

Boost를 사용하여 가능한 해결책은 다음과 같습니다.

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));

이 방법은 방법보다 훨씬 빠를 수 있습니다 stringstream. 그리고 이것은 일반적인 템플릿 함수이기 때문에 모든 종류의 구분자를 사용하여 다른 유형의 문자열 (wchar 등 또는 UTF-8)을 분할하는 데 사용할 수 있습니다.

자세한 내용은 설명서 를 참조하십시오.


답변

#include <vector>
#include <string>
#include <sstream>

int main()
{
    std::string str("Split me by whitespaces");
    std::string buf;                 // Have a buffer string
    std::stringstream ss(str);       // Insert the string into a stream

    std::vector<std::string> tokens; // Create vector to hold our words

    while (ss >> buf)
        tokens.push_back(buf);

    return 0;
}


답변

코드 크기의 모든 효율성을 희생하고 우아함의 일종으로 “효율적인”것을 보는 것이 좋지 않은 사람들에게는 다음과 같은 장점이 있습니다 (템플릿 컨테이너 클래스는 놀랍도록 우아하다고 생각합니다).

template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
              const std::string& delimiters = " ", bool trimEmpty = false)
{
   std::string::size_type pos, lastPos = 0, length = str.length();

   using value_type = typename ContainerT::value_type;
   using size_type  = typename ContainerT::size_type;

   while(lastPos < length + 1)
   {
      pos = str.find_first_of(delimiters, lastPos);
      if(pos == std::string::npos)
      {
         pos = length;
      }

      if(pos != lastPos || !trimEmpty)
         tokens.push_back(value_type(str.data()+lastPos,
               (size_type)pos-lastPos ));

      lastPos = pos + 1;
   }
}

나는 일반적으로 std::vector<std::string>유형을 두 번째 매개 변수 ( ContainerT) 로 사용하도록 선택 하지만 직접 액세스가 필요하지 않을 list<>때보 다 훨씬 빠르며 vector<>자체 문자열 클래스를 만들고 놀라운 속도로 복사를 수행하지 않는 std::list<subString>곳 과 같은 것을 사용할 수도 있습니다 subString증가합니다.

이 페이지에서 가장 빠른 토큰 화보다 두 배 이상 빠르며 다른 것보다 거의 5 배 빠릅니다. 또한 완벽한 매개 변수 유형을 사용하면 모든 문자열 및 목록 사본을 제거하여 추가 속도를 높일 수 있습니다.

또한 결과의 (매우 비효율적 인) 반환을 수행하지는 않지만 대신 토큰을 참조로 전달하므로 원하는 경우 여러 호출을 사용하여 토큰을 작성할 수도 있습니다.

마지막으로 마지막 선택적 매개 변수를 통해 결과에서 빈 토큰을 트리밍할지 여부를 지정할 수 있습니다.

필요한 것은 std::string… 나머지는 선택 사항입니다. 스트림이나 부스트 라이브러리를 사용하지 않지만 이러한 외부 유형 중 일부를 자연스럽게 수용 할 수있을 정도로 유연합니다.


답변

다른 해결책이 있습니다. 컴팩트하고 합리적으로 효율적입니다.

std::vector<std::string> split(const std::string &text, char sep) {
  std::vector<std::string> tokens;
  std::size_t start = 0, end = 0;
  while ((end = text.find(sep, start)) != std::string::npos) {
    tokens.push_back(text.substr(start, end - start));
    start = end + 1;
  }
  tokens.push_back(text.substr(start));
  return tokens;
}

문자열 구분 기호, 넓은 문자열 등을 쉽게 처리 할 수 ​​있습니다.

분할 ""하면 단일 빈 문자열이 생성되고 분할 ","(즉, sep)은 두 개의 빈 문자열이됩니다.

빈 토큰을 건너 뛰도록 쉽게 확장 할 수도 있습니다.

std::vector<std::string> split(const std::string &text, char sep) {
    std::vector<std::string> tokens;
    std::size_t start = 0, end = 0;
    while ((end = text.find(sep, start)) != std::string::npos) {
        if (end != start) {
          tokens.push_back(text.substr(start, end - start));
        }
        start = end + 1;
    }
    if (end != start) {
       tokens.push_back(text.substr(start));
    }
    return tokens;
}

빈 토큰을 건너 뛰면서 여러 구분 기호로 문자열을 분할하려는 경우이 버전을 사용할 수 있습니다.

std::vector<std::string> split(const std::string& text, const std::string& delims)
{
    std::vector<std::string> tokens;
    std::size_t start = text.find_first_not_of(delims), end = 0;

    while((end = text.find_first_of(delims, start)) != std::string::npos)
    {
        tokens.push_back(text.substr(start, end - start));
        start = text.find_first_not_of(delims, end);
    }
    if(start != std::string::npos)
        tokens.push_back(text.substr(start));

    return tokens;
}


답변

이것은 문자열을 반복하는 가장 좋아하는 방법입니다. 단어마다 원하는 것을 할 수 있습니다.

string line = "a line of text to iterate through";
string word;

istringstream iss(line, istringstream::in);

while( iss >> word )
{
    // Do something on `word` here...
}