2012-04-07 254 views
20

我知道这是一个很简单的问题,但我只是想一劳永逸地解决它为我自己和所有将字符串分割一个字符

我只是想用一个字符作为一个字符串分割成一个数组拆分分隔符。 (很像的C#的著名.Split()功能。我当然可以申请蛮力方法,但我不知道是否还有什么比这更好的。

到目前为止,我已经搜查,可能是最接近解决办法是的strtok()的使用,但由于它的不便之处(你的字符串转换为字符数组等)我不喜欢使用它。是否有实现这个任何更简单的方法?

注:我想强调这一点,因为人们可能会问“为什么暴力不行”我的蛮力解决方案是创建一个循环,并使用substr()函数里面。但是,由于它需要起始点和长度,所以在我想分割日期时会失败。因为用户可能会在2012年7月12日或2011年7月3日输入它,在计算'/'分隔符的下一个位置之前,我可以真正了解其长度。

+0

[Splitting String C++]的可能重复(http://stackoverflow.com/questions/275404/splitting-string-c) – 2012-04-08 06:56:41

回答

49

使用矢量,字符串和字符串流。有点麻烦,但它有诀窍。

std::stringstream test("this_is_a_test_string"); 
std::string segment; 
std::vector<std::string> seglist; 

while(std::getline(test, segment, '_')) 
{ 
    seglist.push_back(segment); 
} 
+0

其实这种方法正是我正在寻找的。很容易理解,不使用外部库,只是非常简单。谢谢@thelazydeveloper! – Ali 2012-04-07 22:09:19

+0

仍然是最好的解决方案! – 2018-01-24 12:41:56

2

看看boost::tokenizer

如果你想卷起你自己的方法,你可以使用std::string::find()确定分割点。

+2

谢谢你的字符串查找提示。总是喜欢听** std **解决方案! – Ali 2012-04-07 21:44:58

9

升压有分裂()你正在寻求在algorithm/string.hpp:谁喜欢的人

std::string sample = "07/3/2011"; 
std::vector<string> strs; 
boost::split(strs, sample, boost::is_any_of("/")); 
10

另一种方法(C++ 11 /升压)正则表达式。就我个人而言,我是RegEx对这类数据的忠实粉丝。国际海事组织远比使用分隔符简单地分割字符串更强大,因为如果你愿意,你可以选择是什么构成“有效”数据更聪明。

#include <string> 
#include <algorithm> // copy 
#include <iterator>  // back_inserter 
#include <regex>  // regex, sregex_token_iterator 
#include <vector> 

int main() 
{ 
    std::string str = "08/04/2012"; 
    std::vector<std::string> tokens; 
    std::regex re("\\d+"); 

    //start/end points of tokens in str 
    std::sregex_token_iterator 
     begin(str.begin(), str.end(), re), 
     end; 

    std::copy(begin, end, std::back_inserter(tokens)); 
} 
4

另一种可能性是灌输流与使用特殊ctype端面的语言环境。流使用ctype构面来确定什么是“空白”,它将它视为分隔符。用ctype方法将分隔符字符分类为空格,读取可能非常简单。下面是实施方面的一种方法:

struct field_reader: std::ctype<char> { 

    field_reader(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() { 
     static std::vector<std::ctype_base::mask> 
      rc(table_size, std::ctype_base::mask()); 

     // we'll assume dates are either a/b/c or a-b-c: 
     rc['/'] = std::ctype_base::space; 
     rc['-'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

我们使用,通过使用imbue告诉流使用的语言环境,包括它,然后从流中读取的数据:

std::istringstream in("07/3/2011"); 
in.imbue(std::locale(std::locale(), new field_reader); 

随着该在地方,分裂变得几乎微不足道 - 只用了几个istream_iterator s到从字符串读取的块(这是嵌入在istringstream)初始化向量:

std::vector<std::string>((std::istream_iterator<std::string>(in), 
          std::istream_iterator<std::string>()); 

如果你只在一个地方使用它,这显然会导致矫枉过正。但是,如果你使用它的话,它可以很长的一段时间来保持代码的其余部分非常干净。

0

我内心不喜欢stringstream,虽然我不知道为什么。今天,我写了这个函数,允许用任意字符或字符串将std::string分成一个向量。我知道这个问题很旧,但我想分享另一种拆分std::string的方式。

此代码省略了您从所有结果中拆分出的字符串部分,尽管它可以很容易修改为包含它们。

#include <string> 
#include <vector> 

void split(std::string str, std::string splitBy, std::vector<std::string>& tokens) 
{ 
    /* Store the original string in the array, so we can loop the rest 
    * of the algorithm. */ 
    tokens.push_back(str); 

    // Store the split index in a 'size_t' (unsigned integer) type. 
    size_t splitAt; 
    // Store the size of what we're splicing out. 
    size_t splitLen = splitBy.size(); 
    // Create a string for temporarily storing the fragment we're processing. 
    std::string frag; 
    // Loop infinitely - break is internal. 
    while(true) 
    { 
     /* Store the last string in the vector, which is the only logical 
     * candidate for processing. */ 
     frag = tokens.back(); 
     /* The index where the split is. */ 
     splitAt = frag.find(splitBy); 
     // If we didn't find a new split point... 
     if(splitAt == string::npos) 
     { 
      // Break the loop and (implicitly) return. 
      break; 
     } 
     /* Put everything from the left side of the split where the string 
     * being processed used to be. */ 
     tokens.back() = frag.substr(0, splitAt); 
     /* Push everything from the right side of the split to the next empty 
     * index in the vector. */ 
     tokens.push_back(frag.substr(splitAt+splitLen, frag.size()-(splitAt+splitLen))); 
    } 
} 

要使用,只需调用是这样的...

std::string foo = "This is some string I want to split by spaces."; 
std::vector<std::string> results; 
split(foo, " ", results); 

您现在可以访问随意向量的所有结果。很简单 - 没有stringstream,没有第三方库,也没有退回到C!