【发布时间】:2021-07-12 12:45:58
【问题描述】:
将字符串拆分为字符串向量的正确方法是什么。分隔符是空格或逗号。
【问题讨论】:
-
逗号和空格都是分隔符的拆分,还是根据参数在空格或逗号上拆分的函数?
-
stackoverflow.com/questions/236129/how-to-split-a-string 的一些答案可以很容易地适应多个分隔符。
将字符串拆分为字符串向量的正确方法是什么。分隔符是空格或逗号。
【问题讨论】:
这里是 roach 的解决方案的修改版本,它基于单个字符分隔符的字符串进行拆分 + 支持压缩重复分隔符的选项。
std::vector<std::string> split(std::string text, std::string delim, bool compress)
{
std::vector<std::string> vec;
size_t pos = 0, prevPos = 0;
while (1)
{
pos = text.find_first_of(delim, prevPos);
while(compress)
{
if( prevPos == pos )
prevPos++;
else
break;
pos = text.find_first_of(delim, prevPos);
}
if (pos == std::string::npos) {
if(prevPos != text.size())
vec.push_back(text.substr(prevPos));
return vec;
}
vec.push_back(text.substr(prevPos, pos - prevPos));
prevPos = pos + 1;
}
}
没有压缩的例子:
std::string s = " 1.2 foo@foo . ";
auto res = split(s, ".@ ", false);
for(auto i : res)
std::cout << "string {" << i << "}" << std::endl;
输出:
string {}
string {}
string {1}
string {2}
string {}
string {foo}
string {foo}
string {}
string {}
使用压缩split(s, ".@ ", true);
string {1}
string {2}
string {foo}
string {foo}
【讨论】:
std::vector<std::string> split(std::string text, char delim) {
std::string line;
std::vector<std::string> vec;
std::stringstream ss(text);
while(std::getline(ss, line, delim)) {
vec.push_back(line);
}
return vec;
}
split("String will be split", ' ') -> {"String", "will", "be", "split"}
split("Hello, how are you?", ',') -> {"Hello", "how are you?"}
编辑:这是我做的一个东西,它可以使用多字符分隔符,尽管我不能 100% 确定它是否总是有效:
std::vector<std::string> split(std::string text, std::string delim) {
std::vector<std::string> vec;
size_t pos = 0, prevPos = 0;
while (1) {
pos = text.find(delim, prevPos);
if (pos == std::string::npos) {
vec.push_back(text.substr(prevPos));
return vec;
}
vec.push_back(text.substr(prevPos, pos - prevPos));
prevPos = pos + delim.length();
}
}
【讨论】:
我编写了这个自定义函数,这将对您有所帮助。但是要讨论时间复杂度。
std::vector<std::string> words;
std::string s;
std::string separator = ",";
while(s.find(separator) != std::string::npos){
separatorIndex = s.find(separator)
vtags.push_back(s.substr(0, separatorIndex ));
words= s.substr(separatorIndex + 1, s.length());
}
words.push_back(s);
【讨论】:
来自Techie Delight的调整版本:
#include <string>
#include <vector>
std::vector<std::string> split(const std::string& str, char delim) {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
【讨论】:
对于空格分隔的字符串,你可以这样做:
std::string s = "What is the right way to split a string into a vector of strings";
std::stringstream ss(s);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> vstrings(begin, end);
std::copy(vstrings.begin(), vstrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
输出:
What
is
the
right
way
to
split
a
string
into
a
vector
of
strings
struct tokens: std::ctype<char>
{
tokens(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
typedef std::ctype<char> cctype;
static const cctype::mask *const_rc= cctype::classic_table();
static cctype::mask rc[cctype::table_size];
std::memcpy(rc, const_rc, cctype::table_size * sizeof(cctype::mask));
rc[','] = std::ctype_base::space;
rc[' '] = std::ctype_base::space;
return &rc[0];
}
};
std::string s = "right way, wrong way, correct way";
std::stringstream ss(s);
ss.imbue(std::locale(std::locale(), new tokens()));
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> vstrings(begin, end);
std::copy(vstrings.begin(), vstrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
输出:
right
way
wrong
way
correct
way
【讨论】:
std::vector<std::string> vstrings(begin, end); IMO 会更好,但我想我们不知道提问者是在构建向量,还是希望填充预先存在的向量。
ss.imbue(std::locale(std::locale(), new tokens())) 中创建的令牌结构吗?
auto loc = std::make_shared<tokens>(),然后传递ss.imbue(..., loc.get()));。那应该可以。
你可以使用带分隔符的getline:
string s, tmp;
stringstream ss(s);
vector<string> words;
while(getline(ss, tmp, ',')){
words.push_back(tmp);
.....
}
【讨论】:
vector<string> split(string str, string token){
vector<string>result;
while(str.size()){
int index = str.find(token);
if(index!=string::npos){
result.push_back(str.substr(0,index));
str = str.substr(index+token.size());
if(str.size()==0)result.push_back(str);
}else{
result.push_back(str);
str = "";
}
}
return result;
}
split("1,2,3",",") ==> ["1","2","3"]
split("1,2,",",") ==> ["1","2",""]
split("1token2token3","token") ==> ["1","2","3"]
【讨论】:
我做了这个自定义函数,将线转换为矢量
#include <iostream>
#include <vector>
#include <ctime>
#include <string>
using namespace std;
int main(){
string line;
getline(cin, line);
int len = line.length();
vector<string> subArray;
for (int j = 0, k = 0; j < len; j++) {
if (line[j] == ' ') {
string ch = line.substr(k, j - k);
k = j+1;
subArray.push_back(ch);
}
if (j == len - 1) {
string ch = line.substr(k, j - k+1);
subArray.push_back(ch);
}
}
return 0;
}
【讨论】:
一个方便的方法是boost's string algorithms library。
#include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
#include <boost/algorithm/string/split.hpp> // Include for boost::split
// ...
std::vector<std::string> words;
std::string s;
boost::split(words, s, boost::is_any_of(", "), boost::token_compress_on);
【讨论】:
token_compress_on 是干什么用的?
eCompress(第四个参数)设置为token_compress_on,则相邻的分隔符会合并在一起。否则,每两个分隔符分隔一个标记。 boost.org/doc/libs/1_49_0/doc/html/boost/algorithm/…
如果字符串既有空格又有逗号,可以使用字符串类函数
found_index = myString.find_first_of(delims_str, begin_index)
在一个循环中。检查 != npos 并插入向量中。如果你更喜欢老派,你也可以使用 C's
strtok()
方法。
【讨论】: