用字符拆分字符串

Ali*_*Ali 39 c++ string algorithm

我知道这是一个非常容易的问题,但我只想一劳永逸地解决这个问题

我只想使用字符作为拆分分隔符将字符串拆分为数组.(很像C#着名的.Split()函数.我当然可以应用蛮力方法,但我想知道是否还有更好的方法.

到目前为止,我已经搜索过,可能最接近的解决方案方法是使用strtok(),但由于它的不便(将字符串转换为字符数组等),我不喜欢使用它.有没有更简单的方法来实现这个?

注意:我想强调这一点,因为人们可能会问"蛮力怎么行不通".我的强力解决方案是创建一个循环,并使用里面的substr()函数.但是,由于它需要起点和长度,因此当我想分割日期时它会失败.因为用户可能会在7/12/2012或07/3/2011输入它,在计算"/"分隔符的下一个位置之前,我可以真正地告诉它长度.

小智 81

使用向量,字符串和字符串流.有点麻烦,但它的确如此.

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);
}
Run Code Online (Sandbox Code Playgroud)

这导致具有相同内容的向量

std::vector<std::string> seglist{ "this", "is", "a", "test", "string" };
Run Code Online (Sandbox Code Playgroud)

  • 实际上这种方法正是我正在寻找的。非常容易理解,没有使用外部库,非常简单。谢谢@thelazydeveloper! (2认同)

Ben*_*ell 13

另一种方式(C++ 11/boost)适合喜欢RegEx的人.就我个人而言,我是这种数据的忠实粉丝.IMO它比使用分隔符简单地分割字符串要强大得多,因为如果您愿意,您可以选择更加智能地构建"有效"数据.

#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));
}
Run Code Online (Sandbox Code Playgroud)

  • @Dev 如果对二进制大小有如此极端的限制,那么他们甚至应该重新考虑使用 C++,或者至少使用它的标准库,如字符串/向量/等,因为它们都会产生类似的效果。至于效率,最好的建议来自 Donald Knuth——“过早优化是万恶之源”;换句话说,在进行优化之前,首要任务是确定问题是否存在,然后通过分析等客观手段确定原因,而不是浪费时间试图寻找每一个可能的微观优化。 (4认同)
  • 因此,您在代码中包含整个正则表达式匹配器只是为了拆分字符串。伤心... (2认同)
  • @Dev 否,包括正则表达式匹配器,以便更智能地了解有效数据的构成 - 例如选择数字,并且还允许其他分隔符(例如点或连字符) (2认同)
  • @Dev那么我不得不想知道提出它们的目的是什么。 (2认同)

chr*_*ock 11

Boost有你想要的split()algorithm/string.hpp:

std::string sample = "07/3/2011";
std::vector<string> strs;
boost::split(strs, sample, boost::is_any_of("/"));
Run Code Online (Sandbox Code Playgroud)


Hum*_*ler 10

由于还没有人发布此内容:使用解决方案非常简单ranges。您可以使用 astd::ranges::views::split来分解输入,然后将输入转换为std::stringstd::string_view元素。

#include <ranges>


...

// The input to transform
const auto str = std::string{"Hello World"};

// Function to transform a range into a std::string
// Replace this with 'std::string_view' to make it a view instead.
auto to_string = [](auto&& r) -> std::string {
    const auto data = &*r.begin();
    const auto size = static_cast<std::size_t>(std::ranges::distance(r));

    return std::string{data, size};
};

const auto range = str | 
                   std::ranges::views::split(' ') | 
                   std::ranges::views::transform(to_string);

for (auto&& token : str | range) {
    // each 'token' is the split string
}
Run Code Online (Sandbox Code Playgroud)

这种方法实际上可以组合成任何东西,甚至是一个split返回 a 的简单函数std::vector<std::string>

auto split(const std::string& str, char delimiter) -> std::vector<std::string>
{
    const auto range = str | 
                       std::ranges::views::split(delimiter) | 
                       std::ranges::views::transform(to_string);

    return {std::ranges::begin(range), std::ranges::end(range)};
}
Run Code Online (Sandbox Code Playgroud)

Live Example

  • 与其他答案相比,这有点难以阅读,根本不清楚 (6认同)

Cod*_*e92 5

我本质上不喜欢stringstream,尽管我不确定为什么。今天,我编写了这个函数,允许将std::string任意字符或字符串拆分为向量。我知道这个问题已经很老了,但我想分享一种替代的 split 方式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 == std::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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用,只需像这样调用...

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

您现在可以随意访问向量中的所有结果。就这么简单 - 不stringstream,没有第三方库,不会回到 C!