如何在C ++中标记字符串?
Java有一个方便的split方法:
String str = "The quick brown fox"; String[] results = str.split(" ");
有没有一种简单的方法可以在C ++中做到这一点?
解决方案
回答
没有直接的方法可以做到这一点。请参考此代码项目源代码,以了解如何为此构建类。
回答
这是一个示例令牌生成器类,可能会做我们想要的
//Header file class Tokenizer { public: static const std::string DELIMITERS; Tokenizer(const std::string& str); Tokenizer(const std::string& str, const std::string& delimiters); bool NextToken(); bool NextToken(const std::string& delimiters); const std::string GetToken() const; void Reset(); protected: size_t m_offset; const std::string m_string; std::string m_token; std::string m_delimiters; }; //CPP file const std::string Tokenizer::DELIMITERS(" \t\n\r"); Tokenizer::Tokenizer(const std::string& s) : m_string(s), m_offset(0), m_delimiters(DELIMITERS) {} Tokenizer::Tokenizer(const std::string& s, const std::string& delimiters) : m_string(s), m_offset(0), m_delimiters(delimiters) {} bool Tokenizer::NextToken() { return NextToken(m_delimiters); } bool Tokenizer::NextToken(const std::string& delimiters) { size_t i = m_string.find_first_not_of(delimiters, m_offset); if (std::string::npos == i) { m_offset = m_string.length(); return false; } size_t j = m_string.find_first_of(delimiters, i); if (std::string::npos == j) { m_token = m_string.substr(i); m_offset = m_string.length(); return true; } m_token = m_string.substr(i, j - i); m_offset = j; return true; }
例子:
std::vector <std::string> v; Tokenizer s("split this string", " "); while (s.NextToken()) { v.push_back(s.GetToken()); }
回答
我们可以使用std :: string :: find
方法轻松构建简单的案例。但是,请看一下Boost.Tokenizer。这很棒。 Boost通常具有一些非常酷的字符串工具。
回答
如果我们愿意使用C,则可以使用strtok函数。使用它时,应注意多线程问题。
回答
这是一个真正简单的例子:
#include <vector> #include <string> using namespace std; vector<string> split(const char *str, char c = ' ') { vector<string> result; do { const char *begin = str; while(*str != c && *str) str++; result.push_back(string(begin, str)); } while (0 != *str++); return result; }
回答
我认为这就是字符串流上的>>
运算符的作用:
string word; sin >> word;
回答
我们可以使用流,迭代器和复制算法直接进行此操作。
#include <string> #include <vector> #include <iostream> #include <istream> #include <ostream> #include <iterator> #include <sstream> #include <algorithm> int main() { std::string str = "The quick brown fox"; // construct a stream from the string std::stringstream strstr(str); // use stream iterators to copy the stream to the vector as whitespace separated strings std::istream_iterator<std::string> it(strstr); std::istream_iterator<std::string> end; std::vector<std::string> results(it, end); // send the vector to stdout. std::ostream_iterator<std::string> oit(std::cout); std::copy(results.begin(), results.end(), oit); }
回答
使用strtok。在我看来,除非strtok不能为我们提供所需的内容,否则无需围绕标记化构建类。可能不是,但是在用C和C ++编写各种解析代码的15年以上的时间里,我一直使用strtok。这是一个例子
char myString[] = "The quick brown fox"; char *p = strtok(myString, " "); while (p) { printf ("Token: %s\n", p); p = strtok(NULL, " "); }
一些警告(可能不适合需求)。该字符串在此过程中被"销毁",这意味着EOS字符被内联放置在除臭点中。正确的用法可能要求我们制作字符串的非常量版本。我们还可以更改中间解析的定界符列表。
我个人认为,与编写单独的类相比,以上代码更简单,更易于使用。对我来说,这是该语言提供的功能之一,它做得很好而且干净利落。它只是一个"基于C"的解决方案。这很合适,很容易,而且我们不必编写很多额外的代码:-)
回答
Boost令牌生成器类可以使这种事情变得非常简单:
#include <iostream> #include <string> #include <boost/foreach.hpp> #include <boost/tokenizer.hpp> using namespace std; using namespace boost; int main(int, char**) { string text = "token, test string"; char_separator<char> sep(", "); tokenizer< char_separator<char> > tokens(text, sep); BOOST_FOREACH (const string& t, tokens) { cout << t << "." << endl; } }
针对C ++ 11更新:
#include <iostream> #include <string> #include <boost/tokenizer.hpp> using namespace std; using namespace boost; int main(int, char**) { string text = "token, test string"; char_separator<char> sep(", "); tokenizer<char_separator<char>> tokens(text, sep); for (const auto& t : tokens) { cout << t << "." << endl; } }
回答
Boost具有强大的拆分功能:boost :: algorithm :: split。
示例程序:
#include <vector> #include <boost/algorithm/string.hpp> int main() { auto s = "a,b, c ,,e,f,"; std::vector<std::string> fields; boost::split(fields, s, boost::is_any_of(",")); for (const auto& field : fields) std::cout << "\"" << field << "\"\n"; return 0; }
输出:
"a" "b" " c " "" "e" "f" ""
回答
对于简单的东西,我只使用以下内容:
unsigned TokenizeString(const std::string& i_source, const std::string& i_seperators, bool i_discard_empty_tokens, std::vector<std::string>& o_tokens) { unsigned prev_pos = 0; unsigned pos = 0; unsigned number_of_tokens = 0; o_tokens.clear(); pos = i_source.find_first_of(i_seperators, pos); while (pos != std::string::npos) { std::string token = i_source.substr(prev_pos, pos - prev_pos); if (!i_discard_empty_tokens || token != "") { o_tokens.push_back(i_source.substr(prev_pos, pos - prev_pos)); number_of_tokens++; } pos++; prev_pos = pos; pos = i_source.find_first_of(i_seperators, pos); } if (prev_pos < i_source.length()) { o_tokens.push_back(i_source.substr(prev_pos)); number_of_tokens++; } return number_of_tokens; }
怯ward的免责声明:我编写了实时数据处理软件,其中的数据通过二进制文件,套接字或者某些API调用(I / O卡,相机的)传入。与启动时读取外部配置文件相比,我从未将此功能用于更复杂或者对时间要求不高的事情。
回答
没有冒犯性的人,但是对于这样一个简单的问题,我们使事情变得太复杂了。有很多原因使用Boost。但是对于这种简单的事情,这就像是用20条雪橇击飞苍蝇。
void split( vector<string> & theStringVector, /* Altered/returned value */ const string & theString, const string & theDelimiter) { UASSERT( theDelimiter.size(), >, 0); // My own ASSERT macro. size_t start = 0, end = 0; while ( end != string::npos) { end = theString.find( theDelimiter, start); // If at end, use length=maxLength. Else use length=end-start. theStringVector.push_back( theString.substr( start, (end == string::npos) ? string::npos : end - start)); // If at end, use start=maxSize. Else use start=end+delimiter. start = ( ( end > (string::npos - theDelimiter.size()) ) ? string::npos : end + theDelimiter.size()); } }
例如(以道格为例),
#define SHOW(I,X) cout << "[" << (I) << "]\t " # X " = \"" << (X) << "\"" << endl int main() { vector<string> v; split( v, "A:PEP:909:Inventory Item", ":" ); for (unsigned int i = 0; i < v.size(); i++) SHOW( i, v[i] ); }
是的,我们可以让split()返回一个新向量,而不是传入一个向量。包装和重载都是微不足道的。但是根据我在做什么,我经常发现重用已有的对象而不是总是创建新的对象是更好的选择。 (只要我不忘记将它们之间的向量清空!)
参考:http://www.cplusplus.com/reference/string/string/。
(我最初写的是对道格问题的回答:基于分隔符的C ++字符串修改和提取。
回答
另一种快速的方法是使用getline
。就像是:
stringstream ss("bla bla"); string s; while (getline(ss, s, ' ')) { cout << s << endl; }
如果需要,可以制作一个简单的split()
方法,返回一个vector <string>
,即
真的很有用。
回答
MFC / ATL有一个非常好的标记器。从MSDN:
CAtlString str( "%First Second#Third" ); CAtlString resToken; int curPos= 0; resToken= str.Tokenize("% #",curPos); while (resToken != "") { printf("Resulting token: %s\n", resToken); resToken= str.Tokenize("% #",curPos); }; Output Resulting Token: First Resulting Token: Second Resulting Token: Third
回答
我知道我们要求使用C ++解决方案,但是我们可能会认为这很有帮助:
t
#include <QString> ... QString str = "The quick brown fox"; QStringList results = str.split(" ");
在本示例中,与Boost相比的优势在于,它是直接映射到帖子代码。
在Qt文档中查看更多
回答
检查此示例。它可能会。
#include <iostream> #include <sstream> using namespace std; int main () { string tmps; istringstream is ("the dellimiter is the space"); while (is.good ()) { is >> tmps; cout << tmps << "\n"; } return 0; }