질문자 :Community Wiki
문자열의 단어를 반복하려고합니다.
문자열은 공백으로 구분된 단어로 구성되어 있다고 가정할 수 있습니다.
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", ':');
Community Wiki가치를 위해 표준 라이브러리 기능에만 의존하여 입력 문자열에서 토큰을 추출하는 또 다른 방법이 있습니다. 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>{}};
Community WikiBoost를 사용하는 가능한 솔루션은 다음과 같습니다.
#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)을 분할하는 데 사용할 수 있습니다.
자세한 내용은 설명서 를 참조하십시오.
Community Wiki#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; }
Community Wiki코드 크기를 위해 모든 효율성을 희생하고 우아함의 한 유형으로 "효율적"이라고 생각하는 것이 어울리지 않는 사람들에게는 다음이 최적의 위치에 있어야 합니다(템플릿 컨테이너 클래스는 엄청나게 우아한 추가 사항이라고 생각합니다.).
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; } }
나는 보통 두 번째 매개변수( ContainerT
) std::vector<std::string>
유형을 사용하도록 선택하지만 직접 액세스가 필요하지 않은 경우 list<>
vector<>
보다 훨씬 빠르며 다음을 생성할 수도 있습니다. 자신의 문자열 클래스를 만들고 std::list<subString>
과 같은 것을 사용하십시오. 여기서 subString
은 놀라운 속도 증가를 위해 복사를 수행하지 않습니다.
이 페이지에서 가장 빠른 토큰화보다 두 배 이상 빠르며 다른 페이지보다 거의 5배 빠릅니다. 또한 완벽한 매개변수 유형을 사용하면 추가 속도 증가를 위해 모든 문자열 및 목록 사본을 제거할 수 있습니다.
또한 결과의 (극도로 비효율적인) 반환을 수행하지 않지만 오히려 토큰을 참조로 전달하므로 원하는 경우 여러 호출을 사용하여 토큰을 구축할 수도 있습니다.
마지막으로 마지막 선택적 매개변수를 통해 결과에서 빈 토큰을 트리밍할지 여부를 지정할 수 있습니다.
필요한 것은 std::string
... 나머지는 선택 사항입니다. 스트림이나 부스트 라이브러리를 사용하지 않지만 이러한 외래 유형 중 일부를 자연스럽게 받아들일 수 있을 만큼 충분히 유연합니다.
Community Wiki여기에 또 다른 해결책이 있습니다. 컴팩트하고 합리적으로 효율적입니다.
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; }
Community Wiki이것은 문자열을 반복하는 내가 가장 좋아하는 방법입니다. 단어별로 원하는 대로 할 수 있습니다.
string line = "a line of text to iterate through"; string word; istringstream iss(line, istringstream::in); while( iss >> word ) { // Do something on `word` here... }
Community Wiki이것은 스택 오버플로 질문과 유사 합니다. C++에서 문자열을 어떻게 토큰화합니까? .
#include <iostream> #include <string> #include <boost/tokenizer.hpp> using namespace std; using namespace boost; int main(int argc, char** argv) { string text = "token test\tstring"; char_separator<char> sep(" \t"); tokenizer<char_separator<char>> tokens(text, sep); for (const string& t : tokens) { cout << t << "." << endl; } }
Community Wiki결과를 벡터에 넣고 문자열을 구분 기호로 지원하며 빈 값 유지를 제어할 수 있기 때문에 다음이 마음에 듭니다. 하지만, 그때는 좋지 않아 보인다.
#include <ostream> #include <string> #include <vector> #include <algorithm> #include <iterator> using namespace std; vector<string> split(const string& s, const string& delim, const bool keep_empty = true) { vector<string> result; if (delim.empty()) { result.push_back(s); return result; } string::const_iterator substart = s.begin(), subend; while (true) { subend = search(substart, s.end(), delim.begin(), delim.end()); string temp(substart, subend); if (keep_empty || !temp.empty()) { result.push_back(temp); } if (subend == s.end()) { break; } substart = subend + delim.size(); } return result; } int main() { const vector<string> words = split("So close no matter how far", " "); copy(words.begin(), words.end(), ostream_iterator<string>(cout, "\n")); }
물론 Boost에는 부분적으로 그렇게 작동 split()
그리고 '공백'이 실제로 모든 유형의 공백을 의미하는 경우 is_any_of()
와 함께 Boost의 분할을 사용하면 잘 작동합니다.
Community WikiSTL에는 이미 그러한 방법이 없습니다.
std::string::c_str()
멤버를 사용하여 C의 strtok()
함수를 사용하거나 직접 작성할 수 있습니다. 다음은 빠른 Google 검색( "STL string split" ) 후에 찾은 코드 샘플입니다.
void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ") { // Skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of(delimiters, 0); // Find first "non-delimiter". string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } }
출처: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
코드 샘플에 대해 궁금한 사항이 있으면 댓글을 남겨주시면 설명드리겠습니다.
그리고 iterator라는 typedef
구현하지 않거나 <<
연산자를 오버로드한다고 해서 그것이 잘못된 코드라는 의미는 아닙니다. 나는 C 함수를 꽤 자주 사용한다. 예를 들어, printf
와 scanf
둘 다 std::cin
및 std::cout
보다 빠르며(상당히) fopen
구문은 이진 유형에 훨씬 더 친숙하며 더 작은 EXE를 생성하는 경향이 있습니다.
이 "성능보다 우아함" 거래에 매진하지 마십시오.
Community Wiki다음은 분할 기능입니다.
- 일반적이다
- 표준 C++ 사용(부스트 없음)
- 여러 구분 기호 허용
빈 토큰 무시(쉽게 변경할 수 있음)
template<typename T> vector<T> split(const T & str, const T & delimiters) { vector<T> v; typename T::size_type start = 0; auto pos = str.find_first_of(delimiters, start); while(pos != T::npos) { if(pos != start) // ignore empty tokens v.emplace_back(str, start, pos - start); start = pos + 1; pos = str.find_first_of(delimiters, start); } if(start < str.length()) // ignore trailing delimiter v.emplace_back(str, start, str.length() - start); // add what's left of the string return v; }
사용 예:
vector<string> v = split<string>("Hello, there; World", ";,"); vector<wstring> v = split<wstring>(L"Hello, there; World", L";,");
Community Wiki이 문제에 대한 2줄 솔루션이 있습니다.
char sep = ' '; std::string s="1 This is an example"; for(size_t p=0, q=0; p!=s.npos; p=q) std::cout << s.substr(p+(p!=0), (q=s.find(sep, p+1))-p-(p!=0)) << std::endl;
그런 다음 인쇄하는 대신 벡터에 넣을 수 있습니다.
Community Wiki또 다른 유연하고 빠른 방법
template<typename Operator> void tokenize(Operator& op, const char* input, const char* delimiters) { const char* s = input; const char* e = s; while (*e != 0) { e = s; while (*e != 0 && strchr(delimiters, *e) == 0) ++e; if (e - s > 0) { op(s, e - s); } s = e + 1; } }
문자열 벡터와 함께 사용하려면(편집: 누군가 STL 클래스를 상속하지 말라고 지적했기 때문에... hrmf ;) ):
template<class ContainerType> class Appender { public: Appender(ContainerType& container) : container_(container) {;} void operator() (const char* s, unsigned length) { container_.push_back(std::string(s,length)); } private: ContainerType& container_; }; std::vector<std::string> strVector; Appender v(strVector); tokenize(v, "A number of words to be tokenized", " \t");
그게 다야! 그리고 그것은 단어를 계산하는 방법과 같이 토크나이저를 사용하는 한 가지 방법일 뿐입니다.
class WordCounter { public: WordCounter() : noOfWords(0) {} void operator() (const char*, unsigned) { ++noOfWords; } unsigned noOfWords; }; WordCounter wc; tokenize(wc, "A number of words to be counted", " \t"); ASSERT( wc.noOfWords == 7 );
상상의 한계 ;)
Community Wiki다음은 표준 정규식 라이브러리만 사용하는 간단한 솔루션입니다.
#include <regex> #include <string> #include <vector> std::vector<string> Tokenize( const string str, const std::regex regex ) { using namespace std; std::vector<string> result; sregex_token_iterator it( str.begin(), str.end(), regex, -1 ); sregex_token_iterator reg_end; for ( ; it != reg_end; ++it ) { if ( !it->str().empty() ) //token could be empty:check result.emplace_back( it->str() ); } return result; }
regex 인수를 사용하면 여러 인수(공백, 쉼표 등)를 확인할 수 있습니다.
나는 일반적으로 공백과 쉼표로만 분할하도록 확인하므로 다음과 같은 기본 기능도 있습니다.
std::vector<string> TokenizeDefault( const string str ) { using namespace std; regex re( "[\\s,]+" ); return Tokenize( str, re ); }
"[\\s,]+"
는 공백( \\s
)과 쉼표( ,
)를 확인합니다.
string
대신 wstring
을 분할하려면 참고하십시오.
- 모든
std::regex
를 std::wregex
- 모든
sregex_token_iterator
를 wsregex_token_iterator
컴파일러에 따라 참조로 문자열 인수를 사용할 수도 있습니다.
Community Wikistd::stringstream
을 사용하면 완벽하게 작동하고 원하는 대로 정확하게 수행할 수 있습니다. 다른 일을 수행하는 방법을 찾고 있다면 std::find()
/ std::find_first_of()
및 std::string::substr()
있습니다.
다음은 예입니다.
#include <iostream> #include <string> int main() { std::string s("Somewhere down the road"); std::string::size_type prev_pos = 0, pos = 0; while( (pos = s.find(' ', pos)) != std::string::npos ) { std::string substring( s.substr(prev_pos, pos-prev_pos) ); std::cout << substring << '\n'; prev_pos = ++pos; } std::string substring( s.substr(prev_pos, pos-prev_pos) ); // Last word std::cout << substring << '\n'; return 0; }
Community Wikiboost를 사용하고 싶지만 (이전에 제안된 대부분의 솔루션에서와 같이 단일 문자 대신) 전체 문자열을 구분 기호로 사용하려는 경우 boost_split_iterator
사용할 수 있습니다.
편리한 템플릿을 포함한 예제 코드:
#include <iostream> #include <vector> #include <boost/algorithm/string.hpp> template<typename _OutputIterator> inline void split( const std::string& str, const std::string& delim, _OutputIterator result) { using namespace boost::algorithm; typedef split_iterator<std::string::const_iterator> It; for(It iter=make_split_iterator(str, first_finder(delim, is_equal())); iter!=It(); ++iter) { *(result++) = boost::copy_range<std::string>(*iter); } } int main(int argc, char* argv[]) { using namespace std; vector<string> splitted; split("HelloFOOworldFOO!", "FOO", back_inserter(splitted)); // or directly to console, for example split("HelloFOOworldFOO!", "FOO", ostream_iterator<string>(cout, "\n")); return 0; }
Community Wikistrtok
이라는 함수가 있습니다.
#include<string> using namespace std; vector<string> split(char* str,const char* delim) { char* saveptr; char* token = strtok_r(str,delim,&saveptr); vector<string> result; while(token != NULL) { result.push_back(token); token = strtok_r(NULL,delim,&saveptr); } return result; }
Community Wiki다음은 표준 정규식 라이브러리만 사용하는 정규식 솔루션입니다. (제가 좀 녹슬어서 약간의 문법 오류가 있을 수 있습니다만, 이것은 최소한 일반적인 생각입니다)
#include <regex.h> #include <string.h> #include <vector.h> using namespace std; vector<string> split(string s){ regex r ("\\w+"); //regex matches whole words, (greedy, so no fragment words) regex_iterator<string::iterator> rit ( s.begin(), s.end(), r ); regex_iterator<string::iterator> rend; //iterators to iterate thru words vector<string> result<regex_iterator>(rit, rend); return result; //iterates through the matches to fill the vector }
Community Wiki공백이 아닌 기호로 문자열을 구문 분석해야 하는 경우 stringstream이 편리할 수 있습니다.
string s = "Name:JAck; Spouse:Susan; ..."; string dummy, name, spouse; istringstream iss(s); getline(iss, dummy, ':'); getline(iss, name, ';'); getline(iss, dummy, ':'); getline(iss, spouse, ';')
Community Wikistd::string_view
string_view 및 Eric Niebler의 range-v3
라이브러리 사용:
https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
#include <iostream> #include <string> #include <string_view> #include "range/v3/view.hpp" #include "range/v3/algorithm.hpp" int main() { std::string s = "Somewhere down the range v3 library"; ranges::for_each(s | ranges::view::split(' ') | ranges::view::transform([](auto &&sub) { return std::string_view(&*sub.begin(), ranges::distance(sub)); }), [](auto s) {std::cout << "Substring: " << s << "\n";} ); }
ranges::for_each
알고리즘 대신 for
루프를 사용하여:
#include <iostream> #include <string> #include <string_view> #include "range/v3/view.hpp" int main() { std::string str = "Somewhere down the range v3 library"; for (auto s : str | ranges::view::split(' ') | ranges::view::transform([](auto&& sub) { return std::string_view(&*sub.begin(), ranges::distance(sub)); } )) { std::cout << "Substring: " << s << "\n"; } }
Community Wiki지금까지 Boost 에서 사용했지만 그것에 의존하지 않는 것이 필요했기 때문에 다음과 같이 되었습니다.
static void Split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true) { std::ostringstream word; for (size_t n = 0; n < input.size(); ++n) { if (std::string::npos == separators.find(input[n])) word << input[n]; else { if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); word.str(""); } } if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); }
좋은 점은 separators
에서 둘 이상의 문자를 전달할 수 있다는 것입니다.
Community Wiki짧고 우아한
#include <vector> #include <string> using namespace std; vector<string> split(string data, string token) { vector<string> output; size_t pos = string::npos; // size_t to avoid improbable overflow do { pos = data.find(token); output.push_back(data.substr(0, pos)); if (string::npos != pos) data = data.substr(pos + token.size()); } while (string::npos != pos); return output; }
모든 문자열을 구분 기호로 사용할 수 있으며 이진 데이터와 함께 사용할 수도 있습니다(std::string은 null을 포함한 이진 데이터를 지원함).
사용:
auto a = split("this!!is!!!example!string", "!!");
산출:
this is !example!string
Community WikiC++20은 마침내 split
기능을 제공합니다. 또는 오히려 범위 어댑터. 갓볼트 링크 .
#include <iostream> #include <ranges> #include <string_view> namespace ranges = std::ranges; namespace views = std::views; using str = std::string_view; constexpr auto view = "Multiple words" | views::split(' ') | views::transform([](auto &&r) -> str { return { &*r.begin(), static_cast<str::size_type>(ranges::distance(r)) }; }); auto main() -> int { for (str &&sv : view) { std::cout << sv << '\n'; } }
Community Wiki나는 strtok을 사용하여 내 자신을 굴렸고 부스트를 사용하여 문자열을 분할했습니다. 내가 찾은 가장 좋은 방법은 C++ String Toolkit Library 입니다. 엄청나게 유연하고 빠릅니다.
#include <iostream> #include <vector> #include <string> #include <strtk.hpp> const char *whitespace = " \t\r\n\f"; const char *whitespace_and_punctuation = " \t\r\n\f;,="; int main() { { // normal parsing of a string into a vector of strings std::string s("Somewhere down the road"); std::vector<std::string> result; if( strtk::parse( s, whitespace, result ) ) { for(size_t i = 0; i < result.size(); ++i ) std::cout << result[i] << std::endl; } } { // parsing a string into a vector of floats with other separators // besides spaces std::string s("3.0, 3.14; 4.0"); std::vector<float> values; if( strtk::parse( s, whitespace_and_punctuation, values ) ) { for(size_t i = 0; i < values.size(); ++i ) std::cout << values[i] << std::endl; } } { // parsing a string into specific variables std::string s("angle = 45; radius = 9.9"); std::string w1, w2; float v1, v2; if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) ) { std::cout << "word " << w1 << ", value " << v1 << std::endl; std::cout << "word " << w2 << ", value " << v2 << std::endl; } } return 0; }
이 툴킷은 이 간단한 예가 보여주는 것보다 훨씬 더 유연하지만 문자열을 유용한 요소로 구문 분석하는 유틸리티는 놀랍습니다.
Community Wiki문자열과 C 기반 문자열을 쉽게 분할할 수 있는 방법이 필요했기 때문에 이것을 만들었습니다... 다른 사람도 유용하게 사용할 수 있기를 바랍니다. 또한 토큰에 의존하지 않으며 필드를 구분 기호로 사용할 수 있습니다. 이는 제가 필요한 또 다른 키입니다.
그 우아함을 더욱 향상시킬 수 있는 개선 사항이 있을 거라 확신하며 꼭 해주세요.
StringSplitter.hpp:
#include <vector> #include <iostream> #include <string.h> using namespace std; class StringSplit { private: void copy_fragment(char*, char*, char*); void copy_fragment(char*, char*, char); bool match_fragment(char*, char*, int); int untilnextdelim(char*, char); int untilnextdelim(char*, char*); void assimilate(char*, char); void assimilate(char*, char*); bool string_contains(char*, char*); long calc_string_size(char*); void copy_string(char*, char*); public: vector<char*> split_cstr(char); vector<char*> split_cstr(char*); vector<string> split_string(char); vector<string> split_string(char*); char* String; bool do_string; bool keep_empty; vector<char*> Container; vector<string> ContainerS; StringSplit(char * in) { String = in; } StringSplit(string in) { size_t len = calc_string_size((char*)in.c_str()); String = new char[len + 1]; memset(String, 0, len + 1); copy_string(String, (char*)in.c_str()); do_string = true; } ~StringSplit() { for (int i = 0; i < Container.size(); i++) { if (Container[i] != NULL) { delete[] Container[i]; } } if (do_string) { delete[] String; } } };
StringSplitter.cpp:
#include <string.h> #include <iostream> #include <vector> #include "StringSplit.hpp" using namespace std; void StringSplit::assimilate(char*src, char delim) { int until = untilnextdelim(src, delim); if (until > 0) { char * temp = new char[until + 1]; memset(temp, 0, until + 1); copy_fragment(temp, src, delim); if (keep_empty || *temp != 0) { if (!do_string) { Container.push_back(temp); } else { string x = temp; ContainerS.push_back(x); } } else { delete[] temp; } } } void StringSplit::assimilate(char*src, char* delim) { int until = untilnextdelim(src, delim); if (until > 0) { char * temp = new char[until + 1]; memset(temp, 0, until + 1); copy_fragment(temp, src, delim); if (keep_empty || *temp != 0) { if (!do_string) { Container.push_back(temp); } else { string x = temp; ContainerS.push_back(x); } } else { delete[] temp; } } } long StringSplit::calc_string_size(char* _in) { long i = 0; while (*_in++) { i++; } return i; } bool StringSplit::string_contains(char* haystack, char* needle) { size_t len = calc_string_size(needle); size_t lenh = calc_string_size(haystack); while (lenh--) { if (match_fragment(haystack + lenh, needle, len)) { return true; } } return false; } bool StringSplit::match_fragment(char* _src, char* cmp, int len) { while (len--) { if (*(_src + len) != *(cmp + len)) { return false; } } return true; } int StringSplit::untilnextdelim(char* _in, char delim) { size_t len = calc_string_size(_in); if (*_in == delim) { _in += 1; return len - 1; } int c = 0; while (*(_in + c) != delim && c < len) { c++; } return c; } int StringSplit::untilnextdelim(char* _in, char* delim) { int s = calc_string_size(delim); int c = 1 + s; if (!string_contains(_in, delim)) { return calc_string_size(_in); } else if (match_fragment(_in, delim, s)) { _in += s; return calc_string_size(_in); } while (!match_fragment(_in + c, delim, s)) { c++; } return c; } void StringSplit::copy_fragment(char* dest, char* src, char delim) { if (*src == delim) { src++; } int c = 0; while (*(src + c) != delim && *(src + c)) { *(dest + c) = *(src + c); c++; } *(dest + c) = 0; } void StringSplit::copy_string(char* dest, char* src) { int i = 0; while (*(src + i)) { *(dest + i) = *(src + i); i++; } } void StringSplit::copy_fragment(char* dest, char* src, char* delim) { size_t len = calc_string_size(delim); size_t lens = calc_string_size(src); if (match_fragment(src, delim, len)) { src += len; lens -= len; } int c = 0; while (!match_fragment(src + c, delim, len) && (c < lens)) { *(dest + c) = *(src + c); c++; } *(dest + c) = 0; } vector<char*> StringSplit::split_cstr(char Delimiter) { int i = 0; while (*String) { if (*String != Delimiter && i == 0) { assimilate(String, Delimiter); } if (*String == Delimiter) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return Container; } vector<string> StringSplit::split_string(char Delimiter) { do_string = true; int i = 0; while (*String) { if (*String != Delimiter && i == 0) { assimilate(String, Delimiter); } if (*String == Delimiter) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return ContainerS; } vector<char*> StringSplit::split_cstr(char* Delimiter) { int i = 0; size_t LenDelim = calc_string_size(Delimiter); while(*String) { if (!match_fragment(String, Delimiter, LenDelim) && i == 0) { assimilate(String, Delimiter); } if (match_fragment(String, Delimiter, LenDelim)) { assimilate(String,Delimiter); } i++; String++; } String -= i; delete[] String; return Container; } vector<string> StringSplit::split_string(char* Delimiter) { do_string = true; int i = 0; size_t LenDelim = calc_string_size(Delimiter); while (*String) { if (!match_fragment(String, Delimiter, LenDelim) && i == 0) { assimilate(String, Delimiter); } if (match_fragment(String, Delimiter, LenDelim)) { assimilate(String, Delimiter); } i++; String++; } String -= i; delete[] String; return ContainerS; }
예:
int main(int argc, char*argv[]) { StringSplit ss = "This:CUT:is:CUT:an:CUT:example:CUT:cstring"; vector<char*> Split = ss.split_cstr(":CUT:"); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; }
출력합니다:
이것
~이다
NS
예시
cstring
int main(int argc, char*argv[]) { StringSplit ss = "This:is:an:example:cstring"; vector<char*> Split = ss.split_cstr(':'); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } int main(int argc, char*argv[]) { string mystring = "This[SPLIT]is[SPLIT]an[SPLIT]example[SPLIT]string"; StringSplit ss = mystring; vector<string> Split = ss.split_string("[SPLIT]"); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; } int main(int argc, char*argv[]) { string mystring = "This|is|an|example|string"; StringSplit ss = mystring; vector<string> Split = ss.split_string('|'); for (int i = 0; i < Split.size(); i++) { cout << Split[i] << endl; } return 0; }
빈 항목을 유지하려면(기본적으로 빈 항목은 제외됨):
StringSplit ss = mystring; ss.keep_empty = true; vector<string> Split = ss.split_string(":DELIM:");
목표는 문자열 분할이 다음과 같이 쉬운 C#의 Split() 메서드와 유사하게 만드는 것입니다.
String[] Split = "Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None); foreach(String X in Split) { Console.Write(X); }
다른 사람이 나만큼 유용하게 사용할 수 있기를 바랍니다.
Community Wiki이 답변은 문자열을 가져와 문자열 벡터에 넣습니다. 부스트 라이브러리를 사용합니다.
#include <boost/algorithm/string.hpp> std::vector<std::string> strs; boost::split(strs, "string to split", boost::is_any_of("\t "));
Community Wiki이것은 어떻습니까?
#include <string> #include <vector> using namespace std; vector<string> split(string str, const char delim) { vector<string> v; string tmp; for(string::const_iterator i; i = str.begin(); i <= str.end(); ++i) { if(*i != delim && i != str.end()) { tmp += *i; } else { v.push_back(tmp); tmp = ""; } } return v; }
Community Wiki다른 방법이 있습니다..
void split_string(string text,vector<string>& words) { int i=0; char ch; string word; while(ch=text[i++]) { if (isspace(ch)) { if (!word.empty()) { words.push_back(word); } word = ""; } else { word += ch; } } if (!word.empty()) { words.push_back(word); } }
Community Wiki분할 기준을 지정하는 데 최대한의 유연성을 제공하기 때문에 이 작업에 boost/regex 메서드를 사용하는 것을 좋아합니다.
#include <iostream> #include <string> #include <boost/regex.hpp> int main() { std::string line("A:::line::to:split"); const boost::regex re(":+"); // one or more colons // -1 means find inverse matches aka split boost::sregex_token_iterator tokens(line.begin(),line.end(),re,-1); boost::sregex_token_iterator end; for (; tokens != end; ++tokens) std::cout << *tokens << std::endl; }
Community Wiki최근에 나는 낙타로 된 단어를 하위 단어로 분할해야 했습니다. 구분자는 없고 대문자만 있습니다.
#include <string> #include <list> #include <locale> // std::isupper template<class String> const std::list<String> split_camel_case_string(const String &s) { std::list<String> R; String w; for (String::const_iterator i = s.begin(); i < s.end(); ++i) { { if (std::isupper(*i)) { if (w.length()) { R.push_back(w); w.clear(); } } w += *i; } if (w.length()) R.push_back(w); return R; }
예를 들어, 이것은 "AQueryTrades"를 "A", "Query" 및 "Trades"로 분할합니다. 이 함수는 좁고 넓은 문자열에서 작동합니다. 현재 로케일을 존중하기 때문에 "RaumfahrtÜberwachungsVerordnung"을 "Raumfahrt", "Überwachungs" 및 "Verordnung"으로 나눕니다.
참고 std::upper
는 실제로 함수 템플릿 인수로 전달되어야 합니다. 그런 다음 이 함수를 보다 일반화하면 ","
, ";"
또는 " "
도.
Community Wiki출처 : http:www.stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string