문자열의 단어를 반복하려고합니다.
문자열은 공백으로 구분 된 단어로 구성되어 있다고 가정 할 수 있습니다.
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...
}