将字符串拆分为字符串向量

split a string by a vector of strings

提问人:markt1964 提问时间:8/1/2023 最后编辑:Some programmer dudemarkt1964 更新时间:8/4/2023 访问量:72

问:

我有一个输入字符串,我还有一个分隔符向量。

我想输出不在分隔符中的字符串向量,并作为附加条目输出找到的分隔符

例如,给定

"AB<sep1>DE<sep1><sep2>" where "<sep1>" and "<sep2>" are separators

输出将是向量

"AB", "<sep1>", "DE", "<sep1>", "<sep2>"

有没有一种有效的方法来实现这一点?

C++ stdvector stdstring

评论

0赞 Some programmer dude 8/1/2023
循环中的 findsubstr 函数可能很有用。

答:

0赞 Radovm 8/1/2023 #1

这取决于您希望实现的速度以及极端情况下的预期行为。下面是一个实现示例:

std::string s = "AB<sep1>DE<sep1><sep2>test";
std::vector<std::string> dels = {"<sep1>", "<sep2>"};

size_t pos = 0;
std::vector<std::string> tokens;

for(auto & del : dels)
{
    while ((pos = s.find(del)) != std::string::npos) 
    {
        tokens.push_back(s.substr(0, pos));
        s.erase(0, pos + del.length());
    }
}
if(s.size() != 0)
{
    tokens.push_back(s.substr(0, pos));    
}

for(auto & token : tokens)
{
    std::cout << token << std::endl;
}

输出为:

AB
DE

test

因此,此特定算法将 和 之间的 nothing 视为令牌。<sep1><sep2>

评论

1赞 chrysante 8/1/2023
这个实现被破坏了,请看这里它在测试字符串上的表现。尝试直接在循环之前声明。此外,分隔符标记应该是输出向量的一部分:-)"AB<sep2>BC<sep1>DE<sep1>test"size_t pos = 0;while
1赞 chrysante 8/1/2023 #2

下面是一个可能的实现。

#include <algorithm>
#include <string>
#include <utility>
#include <vector>

std::vector<std::string> split(std::string const& str,
                               std::vector<std::string> const& seps) {
    std::vector<std::pair<size_t, size_t>> sepPos;
    for (auto& sep: seps) {
        if (sep.empty()) {
            continue;
        }
        size_t pos = 0;
        while ((pos = str.find(sep, pos)) != std::string::npos) {
            sepPos.push_back({ pos, pos + sep.size() });
            pos += sep.size();
        }
    }
    std::sort(sepPos.begin(), sepPos.end());
    std::vector<std::string> result;
    size_t pos = 0;
    for (auto [begin, end]: sepPos) {
        result.push_back(str.substr(pos, begin - pos));
        result.push_back(str.substr(begin, end - begin));
        pos = end;
    }
    result.push_back(str.substr(pos, str.size() - pos));
    return result;
}

还有一个最小的测试。

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

#include "Split.h"

int main() {
    auto tokens = split("AB<sep1>DE<sep2>X<sep1>Y", { "<sep1>", "<sep2>" });
    for (auto& token: tokens) {
        std::cout << token << std::endl;
    }
}

它首先查找并收集字符串中所有分隔符实例的位置。然后它对它们进行排序,以便我们可以遍历位置并提取所有子字符串。

请注意,如果一个分隔符包含另一个分隔符作为子字符串,这将崩溃,但我认为这将是一个病态的情况。如果指定了两次分隔符,它也会中断。