문자열의 단어를 어떻게 반복합니까?


질문

 

나는 문자열의 단어를 반복하려고 노력하고 있습니다.

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

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

이 일을하는 더 우아한 방법이 있습니까?


답변

 

나는 이것을 구분 기호로 분할하기 위해 이것을 사용합니다.첫 번째는 사전 구축 된 벡터에서 결과를 두 번째로 올리면 새로운 벡터를 반환합니다.

#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", ':');


답변

그것이 가치가있는 것에 대해, 표준 도서관 시설에서만 의존하는 입력 문자열에서 토큰을 추출하는 또 다른 방법이 있습니다.그것은 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"));
}

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

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

... 또는 벡터 직접 벡터를 만듭니다.

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


답변

부스트를 사용하는 가능한 솔루션은 다음과 같습니다.

#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 유형을 두 번째 매개 변수 (containert)로 사용하지만, 직접 액세스가 필요 없을 때 벡터 <>보다 빨리 <>가 필요합니다.자신의 문자열 클래스를 사용하고 STD :: List 과 같은 것을 사용합니다. 여기서 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;
}
출처:https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string