我正在尝试遍历字符串中的单词。

可以假定字符串由空格分隔的单词组成。

请注意,我对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);
}

有没有更优雅的方法可以做到这一点?


#1楼

我之所以这样做,是因为我需要一种简单的方法来分割字符串和基于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;
}

将输出:

这个

一个

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

我希望其他人能像我一样有用。


#2楼

我对此问题有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;

然后,您可以将其放入向量中,而不是进行打印。


#3楼

这是仅使用标准正则表达式库的正则表达式解决方案。 (我有点生疏,所以可能会有一些语法错误,但这至少是一般性想法)

#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 wordsvector<string> result<regex_iterator>(rit, rend);return result;  //iterates through the matches to fill the vector
}

#4楼

对于那些不愿意为了代码大小而牺牲所有效率并且将“效率”视为一种优雅的人来说,以下内容应该是一个不错的选择(我认为模板容器类是非常出色的添加):

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 ...其余都是可选的。 它不使用流或boost库,但足够灵活以能够自然地接受其中一些外部类型。


#5楼

获取助推 ! :-)

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>using namespace std;
using namespace boost;int main(int argc, char**argv) {typedef vector < string > list_type;list_type list;string line;line = "Somewhere down the road";split(list, line, is_any_of(" "));for(int i = 0; i < list.size(); i++){cout << list[i] << endl;}return 0;
}

这个例子给出了输出-

Somewhere
down
the
road

#6楼

#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;vector<string> split(const string &s, char delim) {vector<string> elems;stringstream ss(s);string item;while (getline(ss, item, delim)) {elems.push_back(item);}return elems;}int main() {vector<string> x = split("thi is an sample test",' ');unsigned int i;for(i=0;i<x.size();i++)cout<<i<<":"<<x[i]<<endl;return 0;
}

#7楼

这是另一种方法。

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

#8楼

我使用strtok滚动了自己的文件,并使用boost来拆分字符串。 我发现的最佳方法是C ++ String Toolkit库 。 它非常灵活和快速。

#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 stringsstd::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 spacesstd::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 variablesstd::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;
}

该工具包比此简单示例显示的灵活性要大得多,但是它在将字符串解析为有用元素方面的实用性令人难以置信。


#9楼

这是仅使用标准正则表达式库的简单解决方案

#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:checkresult.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 )和逗号( , )。

请注意,如果您想分割wstring而不是string

  • 将所有std::regex更改为std::wregex
  • 将所有sregex_token_iterator更改为wsregex_token_iterator

注意,根据您的编译器,您可能还想通过引用获取字符串参数。


#10楼

STL还没有可用的这种方法。

但是,您可以通过使用std::string::c_str()成员来使用C的strtok()函数,也可以编写自己的函数。 这是经过快速Google搜索( “ STL字符串拆分” )后发现的代码示例:

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

如果您对代码示例有疑问,请发表评论,我会解释。

仅仅因为它没有实现称为迭代器的typedef或重载<<操作符,并不意味着它是错误的代码。 我经常使用C函数。 例如, printfscanf都比std::cinstd::cout都快(明显), fopen语法对二进制类型友好得多,并且它们也倾向于生成更小的EXE。

不要因为这项“绩效上的优雅”交易而被出售。


#11楼

这是我最喜欢的遍历字符串的方式。 您可以按单词做任何您想做的事情。

string line = "a line of text to iterate through";
string word;istringstream iss(line, istringstream::in);while( iss >> word )
{// Do something on `word` here...
}

#12楼

使用std::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 wordstd::cout << substring << '\n';return 0;
}

#13楼

我喜欢以下内容,因为它将结果放入向量中,支持字符串作为delim并控制保留空值。 但是,那时看起来还不怎么样。

#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() ,部分工作原理是这样的。 而且,如果使用“空白”,则实际上意味着任何类型的空白,将Boost的split与is_any_of()效果很好。


#14楼

这类似于堆栈溢出问题, 如何在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;}
}

#15楼

我用它用定界符分割字符串。 第一个将结果放入预先构造的向量中,第二个返回一个新向量。

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

#16楼

使用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)。

有关详细信息,请参见文档 。


#17楼

值得的是,这是另一种仅依靠标准库工具从输入字符串中提取令牌的方法。 这是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>{}};

#18楼

另一种灵活而快速的方法

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

受想象力限制;)


#19楼

有一个名为strtok的函数。

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

#20楼

简短而优雅

#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 overflowdo{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

#21楼

到目前为止,我在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可以传递多个字符。


#22楼

这个答案接受字符串并将其放入字符串向量中。 它使用boost库。

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

#23楼

#include <vector>
#include <string>
#include <sstream>int main()
{std::string str("Split me by whitespaces");std::string buf;                 // Have a buffer stringstd::stringstream ss(str);       // Insert the string into a streamstd::vector<std::string> tokens; // Create vector to hold our wordswhile (ss >> buf)tokens.push_back(buf);return 0;
}

#24楼

如果您想使用boost,但想使用整个字符串作为定界符(而不是像大多数先前提出的解决方案中那样使用单个字符),则可以使用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 examplesplit("HelloFOOworldFOO!", "FOO", ostream_iterator<string>(cout, "\n"));return 0;
}

#25楼

我喜欢将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 splitboost::sregex_token_iterator tokens(line.begin(),line.end(),re,-1);boost::sregex_token_iterator end;for (; tokens != end; ++tokens)std::cout << *tokens << std::endl;
}

#26楼

那这个呢:

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

#27楼

如果您需要按非空格符号解析字符串,则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, ';')

#28楼

这是另一个解决方案。 它紧凑且相当有效:

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

#29楼

最近,我不得不将驼峰式单词拆分为子单词。 没有定界符,只有大写字符。

#include <string>
#include <list>
#include <locale> // std::isuppertemplate<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应该真正作为函数模板参数传递。 然后,可以将此函数的更一般化的名称拆分为","";"等分隔符 或" "


#30楼

这是一个拆分函数:

  • 是通用的
  • 使用标准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";,");

如何遍历字符串中的单词?相关推荐

  1. 557. 反转字符串中的单词 III

    557. 反转字符串中的单词 III 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序. 示例: 输入:"Let's take LeetCode cont ...

  2. 【leetcode】557 反转字符串中的单词III(字符串)

    题目链接:https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ 题目描述 给定一个字符串,你需要反转字符串中每个单词的字符顺序 ...

  3. Suzy找到实习了吗Day 8 | 字符串开始啦 344. 反转字符串,541. 反转字符串 II,剑指 Offer 05. 替换空格,151. 反转字符串中的单词,左旋转字符串

    这里是目录 344. 反转字符串 题目 Solution 541. 反转字符串 II 题目 Solution(v1) Solution(v2) 剑指 Offer 05. 替换空格 做题记录 151. ...

  4. Leetcode 557 反转字符串中的单词

    Leetcode 557 反转字符串中的单词 题目描述: 给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序. 示例1: 输入:s = "Let's ...

  5. 将字符串中的单词翻转,不能使用php提供的任何函数 strlen 除外

    将字符串中的单词翻转,不能使用php提供的任何函数 strlen 除外 题目: 写一个函数将字符串中的单词翻转,不能使用php提供的任何函数 strlen 除外. 单词的定义是: 1.只包含字母 2. ...

  6. 从零单刷Leetcode(JAVA描述)—— 557. 反转字符串中的单词 III

    链接:https://leetcode-cn.com/problems/reverse-words-in-a-string-iii 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格 ...

  7. 如何大写字符串中每个单词的第一个字符

    Java中是否内置了一个函数,该函数可以大写字符串中每个单词的第一个字符,而不会影响其他单词? 例子: jon skeet - > Jon Skeet miles o'Brien > Mi ...

  8. LeetCode-字符串-反转字符串中的单词 II

    557. 反转字符串中的单词 III class Solution {public:string reverseWords(string s) {s+=' '; //为了让最后一个单词进入循环stri ...

  9. 习题:统计字符串中的单词个数

    1 /*统计字符串中的单词个数*/ 2 #include<stdio.h> 3 int main(void) 4 { 5 char a[80]={""},c; 6 in ...

最新文章

  1. OpenStack环境搭建(五:附加项虚拟机文件备份使用)
  2. pytorch生成网络WGAN-GP实例
  3. 手把手带你玩转 AWS Lambda
  4. plot与legend画图与图例
  5. mysql dba失业_DBA要失业了?AI优化水平超DBA老炮儿
  6. 在数组中找出3个数使得它们和为0
  7. Web前端学习技巧有哪些?本文给你答案
  8. 谈谈如何利用 valgrind 排查内存错误
  9. ubuntu如何进入超级权限模式,退出超级权限模式,sudo su——root权限
  10. 安卓前端布局Android,Android开发的几种常见布局
  11. mpvue 从零开始 女友拉黑了我 5 不在以下request 合法域名列表中,请参考文档
  12. python 可执行文件打包_使用可执行文件打包Python库
  13. 硬核知识,C/C++移植法则分享
  14. 用单片机测量流体流速的_旋进旋涡流量计的测量原理及优点
  15. java使用Redis(六个类型)
  16. 计算机并口地址定义,电脑并口(LPT)引脚定义
  17. Tiktok/抖音全球用户数据统计
  18. 微商怎么做大做强,教你一套做微商全新打法
  19. php redis 批量发邮件,PHP使用Redis实现订阅发布与批量发送短信
  20. 添加SearchView控件时飘红的问题

热门文章

  1. RelativeLayout 深入理解
  2. Android中XML的命名空间、自定义属性
  3. html语言制作留言条,利用DIV+CSS制作右下角弹出留言板
  4. mysql timdir_MySQL备份之mysqlhotcopy与注意事项
  5. ConcurrentHashMap源码分析(2)——JDK1.8的实现
  6. iOS架构-静态库.framework之依赖第三方库(7)
  7. JavaScript常用DOM集合
  8. 懒人必备:.NetCore快速搭建ELK分布式日志中心
  9. LODOP提示、报错、现象,简短问答
  10. 二叉树原理和作用,总结