阅读背景:

在C ++中拆分一系列空分隔字符串的简单方法

来源:互联网 

I have a series of strings stored in a single array, separated by nulls (for example ['f', 'o', 'o', '

I have a series of strings stored in a single array, separated by nulls (for example ['f', 'o', 'o', '\0', 'b', 'a', 'r', '\0'...]), and I need to split this into a std::vector<std::string> or similar.

我有一系列字符串存储在一个数组中,由空格分隔(例如['f','o','o','\ 0','b','a','r','\ 0'...]),我需要将其拆分为std :: vector 或类似的。

I could just write a 10-line loop to do this using std::find or strlen (in fact I just did), but I'm wondering if there is a simpler/more elegant way to do it, for example some STL algorithm I've overlooked, which can be coaxed into doing this.

我可以使用std :: find或strlen编写一个10行循环来实现这一点(事实上我刚刚做了),但我想知道是否有更简单/更优雅的方法来做,例如一些STL算法我忽略了,可以哄骗这样做。

It is a fairly simple task, and it wouldn't surprise me if there's some clever STL trickery that can be applied to make it even simpler.

这是一个相当简单的任务,如果有一些聪明的STL技巧可以应用于使其更简单,我也不会感到惊讶。

Any takers?

7 个解决方案

#1


35  

My two cents :

我的两分钱:

const char* p = str;
std::vector<std::string> vector;

do {
  vector.push_back(std::string(p));
  p += vector.back().size() + 1;
} while ( // whatever condition applies );

#2


8  

Boost solution:

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
//input_array must be a Range containing the input.
boost::split(
    strs,
    input_array,
    boost::is_any_of(boost::as_array("\0")));

#3


6  

The following relies on std::string having an implicit constructor taking a const char*, making the loop a very simple two-liner:

以下依赖于std :: string,它具有一个带有const char *的隐式构造函数,使得循环变得非常简单:

#include <iostream>
#include <string>
#include <vector>

template< std::size_t N >
std::vector<std::string> split_buffer(const char (&buf)[N])
{
    std::vector<std::string> result;

    for(const char* p=buf; p!=buf+sizeof(buf); p+=result.back().size()+1)
        result.push_back(p);

    return result;
}

int main()
{
    std::vector<std::string> test = split_buffer("wrgl\0brgl\0frgl\0srgl\0zrgl");

    for (auto it = test.begin(); it != test.end(); ++it)
        std::cout << '"' << *it << "\"\n";

    return 0;
}

This solution assumes the buffer's size is known and the criterion for the end of the list of strings. If the list is terminated by "\0\0" instead, the condition in the loop needs to be changed from p!=foo+sizeof(foo) to *p.

此解决方案假定缓冲区的大小已知,并且是字符串列表结尾的标准。如果列表以“\ 0 \ 0”结尾,则循环中的条件需要从p!= foo + sizeof(foo)更改为* p。

#4


2  

Here's the solution I came up with myself, assuming the buffer ends immediately after the last string:

这是我自己提出的解决方案,假设缓冲区在最后一个字符串之后立即结束:

std::vector<std::string> split(const std::vector<char>& buf) {
    auto cur = buf.begin();
    while (cur != buf.end()) {
        auto next = std::find(cur, buf.end(), '\0');
        drives.push_back(std::string(cur, next));
        cur = next + 1;
    }
    return drives;
}

#5


1  

A bad answer, actually, but I doubted your claim of a 10 line loop for manual splitting. 4 Lines do it for me:

实际上,这是一个糟糕的答案,但我怀疑你对手动分割的10行循环的主张。 4行为我做:

#include <vector>
#include <iostream>
int main() {
    using std::vector;

    const char foo[] = "meh\0heh\0foo\0bar\0frob";

    vector<vector<char> > strings(1);
    for (const char *it=foo, *end=foo+sizeof(foo); it!=end; ++it) {
        strings.back().push_back(*it);
        if (*it == '\0') strings.push_back(vector<char>());
    }

    std::cout << "number of strings: " << strings.size() << '\n';
    for (vector<vector<char> >::iterator it=strings.begin(), end=strings.end(); 
         it!=end; ++it)
        std::cout << it->data() << '\n';
}

#6


1  

A more elegant and actual solution (compared to my other answer) uses getline and boils down to 2 lines with only C++2003, and no manual loop bookkeeping and conditioning is required:

一个更优雅和实际的解决方案(与我的其他答案相比)使用getline并且仅使用C ++ 2003可以归结为2行,并且不需要手动循环簿记和调节:

#include <iostream>
#include <sstream>
#include <string>

int main() {
    const char foo[] = "meh\0heh\0foo\0bar\0frob";

    std::istringstream ss (std::string(foo, foo + sizeof foo));
    std::string str;

    while (getline (ss, str, '\0'))
        std::cout << str << '\n';
}

However, note how the range based string constructor already indicates an inherent problem with splitting-at-'\0's: You must know the exact size, or find some other char-combo for the Ultimate Terminator.

但是,请注意基于范围的字符串构造函数如何已经指示了拆分的固有问题 - '\ 0':您必须知道确切的大小,或者为Ultimate Terminator找到一些其他的char-combo。

#7


-9  

In C, string.h has this guy:

在C中,string.h有这个人:

char * strtok ( char * str, const char * delimiters );

the example on cplusplus.com :

cplusplus.com上的示例:

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

It's not C++, but it will work

它不是C ++,但它会起作用


', 'b', 'a', 'r', '

I have a series of strings stored in a single array, separated by nulls (for example ['f', 'o', 'o', '\0', 'b', 'a', 'r', '\0'...]), and I need to split this into a std::vector<std::string> or similar.

我有一系列字符串存储在一个数组中,由空格分隔(例如['f','o','o','\ 0','b','a','r','\ 0'...]),我需要将其拆分为std :: vector 或类似的。

I could just write a 10-line loop to do this using std::find or strlen (in fact I just did), but I'm wondering if there is a simpler/more elegant way to do it, for example some STL algorithm I've overlooked, which can be coaxed into doing this.

我可以使用std :: find或strlen编写一个10行循环来实现这一点(事实上我刚刚做了),但我想知道是否有更简单/更优雅的方法来做,例如一些STL算法我忽略了,可以哄骗这样做。

It is a fairly simple task, and it wouldn't surprise me if there's some clever STL trickery that can be applied to make it even simpler.

这是一个相当简单的任务,如果有一些聪明的STL技巧可以应用于使其更简单,我也不会感到惊讶。

Any takers?

7 个解决方案

#1


35  

My two cents :

我的两分钱:

const char* p = str;
std::vector<std::string> vector;

do {
  vector.push_back(std::string(p));
  p += vector.back().size() + 1;
} while ( // whatever condition applies );

#2


8  

Boost solution:

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
//input_array must be a Range containing the input.
boost::split(
    strs,
    input_array,
    boost::is_any_of(boost::as_array("\0")));

#3


6  

The following relies on std::string having an implicit constructor taking a const char*, making the loop a very simple two-liner:

以下依赖于std :: string,它具有一个带有const char *的隐式构造函数,使得循环变得非常简单:

#include <iostream>
#include <string>
#include <vector>

template< std::size_t N >
std::vector<std::string> split_buffer(const char (&buf)[N])
{
    std::vector<std::string> result;

    for(const char* p=buf; p!=buf+sizeof(buf); p+=result.back().size()+1)
        result.push_back(p);

    return result;
}

int main()
{
    std::vector<std::string> test = split_buffer("wrgl\0brgl\0frgl\0srgl\0zrgl");

    for (auto it = test.begin(); it != test.end(); ++it)
        std::cout << '"' << *it << "\"\n";

    return 0;
}

This solution assumes the buffer's size is known and the criterion for the end of the list of strings. If the list is terminated by "\0\0" instead, the condition in the loop needs to be changed from p!=foo+sizeof(foo) to *p.

此解决方案假定缓冲区的大小已知,并且是字符串列表结尾的标准。如果列表以“\ 0 \ 0”结尾,则循环中的条件需要从p!= foo + sizeof(foo)更改为* p。

#4


2  

Here's the solution I came up with myself, assuming the buffer ends immediately after the last string:

这是我自己提出的解决方案,假设缓冲区在最后一个字符串之后立即结束:

std::vector<std::string> split(const std::vector<char>& buf) {
    auto cur = buf.begin();
    while (cur != buf.end()) {
        auto next = std::find(cur, buf.end(), '\0');
        drives.push_back(std::string(cur, next));
        cur = next + 1;
    }
    return drives;
}

#5


1  

A bad answer, actually, but I doubted your claim of a 10 line loop for manual splitting. 4 Lines do it for me:

实际上,这是一个糟糕的答案,但我怀疑你对手动分割的10行循环的主张。 4行为我做:

#include <vector>
#include <iostream>
int main() {
    using std::vector;

    const char foo[] = "meh\0heh\0foo\0bar\0frob";

    vector<vector<char> > strings(1);
    for (const char *it=foo, *end=foo+sizeof(foo); it!=end; ++it) {
        strings.back().push_back(*it);
        if (*it == '\0') strings.push_back(vector<char>());
    }

    std::cout << "number of strings: " << strings.size() << '\n';
    for (vector<vector<char> >::iterator it=strings.begin(), end=strings.end(); 
         it!=end; ++it)
        std::cout << it->data() << '\n';
}

#6


1  

A more elegant and actual solution (compared to my other answer) uses getline and boils down to 2 lines with only C++2003, and no manual loop bookkeeping and conditioning is required:

一个更优雅和实际的解决方案(与我的其他答案相比)使用getline并且仅使用C ++ 2003可以归结为2行,并且不需要手动循环簿记和调节:

#include <iostream>
#include <sstream>
#include <string>

int main() {
    const char foo[] = "meh\0heh\0foo\0bar\0frob";

    std::istringstream ss (std::string(foo, foo + sizeof foo));
    std::string str;

    while (getline (ss, str, '\0'))
        std::cout << str << '\n';
}

However, note how the range based string constructor already indicates an inherent problem with splitting-at-'\0's: You must know the exact size, or find some other char-combo for the Ultimate Terminator.

但是,请注意基于范围的字符串构造函数如何已经指示了拆分的固有问题 - '\ 0':您必须知道确切的大小,或者为Ultimate Terminator找到一些其他的char-combo。

#7


-9  

In C, string.h has this guy:

在C中,string.h有这个人:

char * strtok ( char * str, const char * delimiters );

the example on cplusplus.com :

cplusplus.com上的示例:

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

It's not C++, but it will work

它不是C ++,但它会起作用


'...]), and I need to split this into a I have a series of strings stored in a single a




你的当前访问异常,请进行认证后继续阅读剩余内容。

分享到: