如何迭代由空格分隔的单词组成的字符串中的单词?
注意,我对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);
}
我已经使用strtok滚动了自己的代码,并使用boost拆分了一个字符串。我找到的最好的方法是C++字符串工具包库。它非常灵活和快速。
#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;
}
该工具包比这个简单示例显示的灵活性要高得多,但它在将字符串解析为有用元素方面的实用性令人难以置信。
#include <iostream>
#include <string>
#include <deque>
std::deque<std::string> split(
const std::string& line,
std::string::value_type delimiter,
bool skipEmpty = false
) {
std::deque<std::string> parts{};
if (!skipEmpty && !line.empty() && delimiter == line.at(0)) {
parts.push_back({});
}
for (const std::string::value_type& c : line) {
if (
(
c == delimiter
&&
(skipEmpty ? (!parts.empty() && !parts.back().empty()) : true)
)
||
(c != delimiter && parts.empty())
) {
parts.push_back({});
}
if (c != delimiter) {
parts.back().push_back(c);
}
}
if (skipEmpty && !parts.empty() && parts.back().empty()) {
parts.pop_back();
}
return parts;
}
void test(const std::string& line) {
std::cout << line << std::endl;
std::cout << "skipEmpty=0 |";
for (const std::string& part : split(line, ':')) {
std::cout << part << '|';
}
std::cout << std::endl;
std::cout << "skipEmpty=1 |";
for (const std::string& part : split(line, ':', true)) {
std::cout << part << '|';
}
std::cout << std::endl;
std::cout << std::endl;
}
int main() {
test("foo:bar:::baz");
test("");
test("foo");
test(":");
test("::");
test(":foo");
test("::foo");
test(":foo:");
test(":foo::");
return 0;
}
输出:
foo:bar:::baz
skipEmpty=0 |foo|bar|||baz|
skipEmpty=1 |foo|bar|baz|
skipEmpty=0 |
skipEmpty=1 |
foo
skipEmpty=0 |foo|
skipEmpty=1 |foo|
:
skipEmpty=0 |||
skipEmpty=1 |
::
skipEmpty=0 ||||
skipEmpty=1 |
:foo
skipEmpty=0 ||foo|
skipEmpty=1 |foo|
::foo
skipEmpty=0 |||foo|
skipEmpty=1 |foo|
:foo:
skipEmpty=0 ||foo||
skipEmpty=1 |foo|
:foo::
skipEmpty=0 ||foo|||
skipEmpty=1 |foo|
对于一个大得离谱而且可能是冗余的版本,可以尝试很多For循环。
string stringlist[10];
int count = 0;
for (int i = 0; i < sequence.length(); i++)
{
if (sequence[i] == ' ')
{
stringlist[count] = sequence.substr(0, i);
sequence.erase(0, i+1);
i = 0;
count++;
}
else if (i == sequence.length()-1) // Last word
{
stringlist[count] = sequence.substr(0, i+1);
}
}
它并不漂亮,但总的来说(除了标点符号和一系列其他错误)它是有效的!
并不是说我们需要更多的答案,但这是我受到埃文·特兰启发后想到的。
std::vector <std::string> split(const string &input, auto delimiter, bool skipEmpty=true) {
/*
Splits a string at each delimiter and returns these strings as a string vector.
If the delimiter is not found then nothing is returned.
If skipEmpty is true then strings between delimiters that are 0 in length will be skipped.
*/
bool delimiterFound = false;
int pos=0, pPos=0;
std::vector <std::string> result;
while (true) {
pos = input.find(delimiter,pPos);
if (pos != std::string::npos) {
if (skipEmpty==false or pos-pPos > 0) // if empty values are to be kept or not
result.push_back(input.substr(pPos,pos-pPos));
delimiterFound = true;
} else {
if (pPos < input.length() and delimiterFound) {
if (skipEmpty==false or input.length()-pPos > 0) // if empty values are to be kept or not
result.push_back(input.substr(pPos,input.length()-pPos));
}
break;
}
pPos = pos+1;
}
return result;
}
我的代码是:
#include <list>
#include <string>
template<class StringType = std::string, class ContainerType = std::list<StringType> >
class DSplitString:public ContainerType
{
public:
explicit DSplitString(const StringType& strString, char cChar, bool bSkipEmptyParts = true)
{
size_t iPos = 0;
size_t iPos_char = 0;
while(StringType::npos != (iPos_char = strString.find(cChar, iPos)))
{
StringType strTemp = strString.substr(iPos, iPos_char - iPos);
if((bSkipEmptyParts && !strTemp.empty()) || (!bSkipEmptyParts))
push_back(strTemp);
iPos = iPos_char + 1;
}
}
explicit DSplitString(const StringType& strString, const StringType& strSub, bool bSkipEmptyParts = true)
{
size_t iPos = 0;
size_t iPos_char = 0;
while(StringType::npos != (iPos_char = strString.find(strSub, iPos)))
{
StringType strTemp = strString.substr(iPos, iPos_char - iPos);
if((bSkipEmptyParts && !strTemp.empty()) || (!bSkipEmptyParts))
push_back(strTemp);
iPos = iPos_char + strSub.length();
}
}
};
例子:
#include <iostream>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
DSplitString<> aa("doicanhden1;doicanhden2;doicanhden3;", ';');
for each (std::string var in aa)
{
std::cout << var << std::endl;
}
std::cin.get();
return 0;
}