Bil*_*ard 400 c++ string split tokenize
Java有一个方便的拆分方法:
String str = "The quick brown fox";
String[] results = str.split(" ");
Run Code Online (Sandbox Code Playgroud)
有没有一种简单的方法在C++中执行此操作?
Fer*_*cio 187
该升压标记生成器类可以使这种相当简单的事情:
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
针对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;
}
}
Run Code Online (Sandbox Code Playgroud)
Ada*_*rce 168
这是一个非常简单的:
#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;
}
Run Code Online (Sandbox Code Playgroud)
Kon*_*lph 140
您可以使用该std::string::find方法轻松构建简单的案例.但是,看看Boost.Tokenizer.这很棒.Boost通常有一些非常酷的字符串工具.
Mar*_*ark 113
使用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, " ");
}
Run Code Online (Sandbox Code Playgroud)
一些警告(可能不适合您的需要).字符串在此过程中被"销毁",这意味着EOS字符内嵌在分隔符中.正确使用可能需要您创建字符串的非const版本.您还可以在解析时更改分隔符列表.
在我看来,上面的代码比为它编写一个单独的类要简单得多,也更容易使用.对我来说,这是该语言提供的那些功能之一,并且它干净利落地完成了它.它只是一个"基于C"的解决方案.这很合适,很简单,而且你不必编写很多额外的代码:-)
use*_*978 99
另一种快速方法是使用getline.就像是:
stringstream ss("bla bla");
string s;
while (getline(ss, s, ' ')) {
cout << s << endl;
}
Run Code Online (Sandbox Code Playgroud)
如果你愿意,你可以做一个简单的split()方法返回一个vector<string>,这是非常有用的.
Kei*_*thB 82
您可以使用流,迭代器和复制算法直接执行此操作.
#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);
}
Run Code Online (Sandbox Code Playgroud)
Mr.*_*Ree 46
没有进攻的乡亲,但对于这样一个简单的问题,你在做事情的方式太复杂了.使用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());
}
}
Run Code Online (Sandbox Code Playgroud)
例如(对于Doug的案例),
#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] );
}
Run Code Online (Sandbox Code Playgroud)
是的,我们可以让split()返回一个新的向量,而不是传入一个.包装和重载是微不足道的.但是根据我正在做的事情,我经常发现重新使用预先存在的对象而不是总是创建新对象会更好.(只要我不忘记在中间清空矢量!)
参考:http://www.cplusplus.com/reference/string/string/.
(我最初写的回答Doug的问题:基于分隔符的C++字符串修改和提取(已关闭).但是由于Martin York用指针关闭了这个问题......我只是概括了我的代码.)
w.b*_*w.b 41
使用regex_token_iterators 的解决方案:
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main()
{
string str("The quick brown fox");
regex reg("\\s+");
sregex_token_iterator iter(str.begin(), str.end(), reg, -1);
sregex_token_iterator end;
vector<string> vec(iter, end);
for (auto a : vec)
{
cout << a << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
Raz*_*Raz 34
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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
"a"
"b"
" c "
""
"e"
"f"
""
Run Code Online (Sandbox Code Playgroud)
siv*_*udh 25
我知道您要求提供C++解决方案,但您可能会认为这有用:
Qt的
#include <QString>
...
QString str = "The quick brown fox";
QStringList results = str.split(" ");
Run Code Online (Sandbox Code Playgroud)
在这个例子中,优于Boost的优势在于它是一个一对一的映射到你的帖子的代码.
vzc*_*czc 22
这是一个示例tokenizer类,可以执行您想要的操作
//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;
}
Run Code Online (Sandbox Code Playgroud)
例:
std::vector <std::string> v;
Tokenizer s("split this string", " ");
while (s.NextToken())
{
v.push_back(s.GetToken());
}
Run Code Online (Sandbox Code Playgroud)
Par*_*ham 18
这是一个简单的仅限STL的解决方案(约5行!)std::find,std::find_first_not_of它使用并处理分隔符的重复(例如空格或句点),以及前导和尾随分隔符:
#include <string>
#include <vector>
void tokenize(std::string str, std::vector<string> &token_v){
size_t start = str.find_first_not_of(DELIMITER), end=start;
while (start != std::string::npos){
// Find next occurence of delimiter
end = str.find(DELIMITER, start);
// Push back the token found into vector
token_v.push_back(str.substr(start, end-start));
// Skip all occurences of the delimiter to find new start
start = str.find_first_not_of(DELIMITER, end);
}
}
Run Code Online (Sandbox Code Playgroud)
试试吧直播!
dbr*_*dbr 16
pystring是一个小型库,它实现了一堆Python的字符串函数,包括split方法:
#include <string>
#include <vector>
#include "pystring.h"
std::vector<std::string> chunks;
pystring::split("this string", chunks);
// also can specify a separator
pystring::split("this-string", chunks, "-");
Run Code Online (Sandbox Code Playgroud)
ein*_*ica 12
如果您使用 C++ 范围 - 完整的range-v3库,而不是 C++20 接受的有限功能 - 您可以这样做:
auto results = str | ranges::views::tokenize(" ",1);
Run Code Online (Sandbox Code Playgroud)
...这是懒惰评估的。您也可以将向量设置为此范围:
auto results = str | ranges::views::tokenize(" ",1) | ranges::to<std::vector>();
Run Code Online (Sandbox Code Playgroud)
str如果有 n 个字符组成 m 个单词,则需要 O(m) 空间和 O(n) 时间。
另请参阅库自己的标记化示例,此处。
Dan*_*nyK 10
我发布了类似问题的答案.
不要重新发明轮子.我使用了许多库,我遇到的最快和最灵活的是: C++ String Toolkit Library.
这是一个如何使用它的例子,我已经发布了stackoverflow上的其他地方.
#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;
}
Run Code Online (Sandbox Code Playgroud)
小智 8
检查此示例.它可能会帮助你..
#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;
}
Run Code Online (Sandbox Code Playgroud)
Adam Pierce 的回答提供了一个手工标记的分词器,将const char*. 使用迭代器有点问题,因为递增 astring的结束迭代器是 undefined。也就是说,鉴于string str{ "The quick brown fox" }我们当然可以做到这一点:
auto start = find(cbegin(str), cend(str), ' ');
vector<string> tokens{ string(cbegin(str), start) };
while (start != cend(str)) {
const auto finish = find(++start, cend(str), ' ');
tokens.push_back(string(start, finish));
start = finish;
}
Run Code Online (Sandbox Code Playgroud)
如果您希望通过使用标准功能来抽象复杂性,正如On Freund 建议的那样,这 strtok是一个简单的选择:
vector<string> tokens;
for (auto i = strtok(data(str), " "); i != nullptr; i = strtok(nullptr, " ")) tokens.push_back(i);
Run Code Online (Sandbox Code Playgroud)
如果您无权访问 C++17,则需要data(str)像本示例中那样替换:http : //ideone.com/8kAGoa
尽管示例中没有演示,但strtok不必为每个标记使用相同的分隔符。除了这个优势,还有几个缺点:
strtok不能在多个可使用strings在同一时间:无论是nullptr必须传递给继续标记化的当前string或新的char*来标记必须被传递(也有其做然而支持这一点,如一些非标准的实现:strtok_s)strtok,不能同时在多个线程上使用(但这可能是实现定义的,例如:Visual Studio 的实现是线程安全的)strtok修改了string它正在操作的对象,因此它不能用于const strings、const char*s 或文字字符串,以标记其中的任何一个strtok或对string需要保留的内容进行操作,str必须被复制,然后副本可以被操作c++20为我们提供了split_view以非破坏性方式标记字符串的方法:https ://topanswers.xyz/cplusplus?q=749#a874
前面的方法不能vector就地生成标记化,这意味着如果不将它们抽象为辅助函数,它们就无法初始化const vector<string> tokens。该功能和接受任何空白分隔符的能力可以使用istream_iterator. 例如给出:const string str{ "The quick \tbrown \nfox" }我们可以这样做:
istringstream is{ str };
const vector<string> tokens{ istream_iterator<string>(is), istream_iterator<string>() };
Run Code Online (Sandbox Code Playgroud)
istringstream此选项所需的构造成本远高于前 2 个选项,但此成本通常隐藏在string分配费用中。
如果上述选项都不能满足您的标记化需求,那么最灵活的选项regex_token_iterator当然是使用具有这种灵活性的更大费用,但这同样可能隐藏在string分配成本中。例如,假设我们想要基于非转义逗号进行标记,也吃空格,给定以下输入:const string str{ "The ,qu\\,ick ,\tbrown, fox" }我们可以这样做:
const regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
const vector<string> tokens{ sregex_token_iterator(cbegin(str), cend(str), re, 1), sregex_token_iterator() };
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
532986 次 |
| 最近记录: |