【问题标题】:Erase inside a std::string by std::string_view通过 std::string_view 在 std::string 中擦除
【发布时间】:2020-05-06 15:39:56
【问题描述】:

我需要找到并删除字符串的一部分(子字符串)。 string_view 似乎是个好主意,但我无法让它与 string::erase 一起使用:

// guaranteed to return a view into `str`
auto gimme_gimme_gimme(const std::string& str) -> std::string_view;

auto after_midnight(std::string& str)
{
    auto man = gimme_gimme_gimme(str);

    str.erase(man); // way to hopeful, not a chance though
    str.erase(man.begin(), man.end()); // nope
    str.erase(std::distance(str.begin(), man.begin()), man.size()); // nope
    str.erase(std::distance(str.data(), man.data()), man.size()); // nope again

    // for real???
}

我是不是想多了?给定一个std::string_view 到一个std::string 如何擦除字符串的那部分?还是我滥用string_view

【问题讨论】:

  • 我不会在这里使用 string_view。我要么返回一个pair<size_t, size_t>,其中first 是子字符串的索引,second 是长度,或者只是修改gimme_gimme_gimme 以实际进行擦除。
  • 当您说“擦除字符串的一部分”时,您是什么意思?如果字符串是“abbabca”,而字符串视图是“ab”,那么你到底想删除什么?
  • @eerorika 一个子字符串。在您的示例中,如果我了解视图位于字符串的前两个字符中,则擦除会给出"ba"
  • @bolov 我编辑了我的评论
  • @eerorika 哦,我明白了。我的意思是原始字符串的子字符串。 string_view 是原始字符串的视图,它不指向另一个对象。

标签: c++ string c++17 string-view


【解决方案1】:

字符串视图可能确实是空的,或者它可能是容器外部的视图。您建议的erase 重载以及答案中函数的实现依赖于字符串视图是相同字符串对象的前提条件。

当然,迭代器重载非常相似,并且依赖于相同的前置条件。但是这样的前置条件对于迭代器来说是常规的,但对于字符串视图来说是非常规的。

在这种情况下,我认为字符串视图不是表示子范围的理想方式。相反,我建议使用基于索引的相对子范围。例如:

struct sub_range {
    size_t begin;
    size_t count;
    constexpr size_t past_end() noexcept {
        return begin + count;
    }
};

对于第二个成员是否使用end(即past_end)或count,并提供另一个作为函数是一个口味问题。无论如何,不​​应该有混淆,因为该成员将有一个名字。对索引使用 count 比较传统。

另一个选择是使用有符号或无符号索引。有符号索引可用于表示向后范围。但是std::string 接口不理解这样的范围。

示例用法:

auto gimme_gimme_gimme(const std::string& str) -> sub_range;

auto after_midnight(std::string& str)
{
    auto man = gimme_gimme_gimme(str);
    str.erase(man.begin, man.distance);
}

【讨论】:

    【解决方案2】:

    我是不是想多了?

    除非我遗漏了一些明显的东西,否则你正在考虑它。要编译代码,您需要:

    auto gimme_gimme_gimme(const std::string& str) -> std::string_view;
    
    auto after_midnight(std::string& str)
    {
        auto man = gimme_gimme_gimme(str);
    
        str.erase(std::distance(std::as_const(str).data(), man.data()), man.size()); // urrr... growling in pain
    }
    

    但是等等!!还有更多!注意我说“让它编译”。代码容易出错!!因为……

    std::string::data 不能为 nullptr,但空的 string_view 可以表示为(字符串内的有效指针 + 大小 0)或(nullptr + 大小 0)。如果string_view::datanulltpr,则会出现问题,因为使用了std::distance

    所以你需要确保string_view 总是指向字符串内部,即使视图是空的。或者在擦除方面做额外的检查。

    【讨论】:

    • 我是否遗漏了一些明显的东西?
    猜你喜欢
    • 2021-12-29
    • 2020-03-24
    • 1970-01-01
    • 2022-10-24
    • 2017-02-28
    • 2020-04-12
    • 2021-08-11
    • 2017-11-22
    相关资源
    最近更新 更多