Std::locale按特定字符分割字符串而不忽略它

std::locale to split string by specific char without ignoring it

本文关键字:字符串 字符 locale Std 分割      更新时间:2023-10-16

我想按特定字符分割字符串,而不忽略它们。

例如,如果我有字符串:

"some_tag = some_value"

我可以使用这个区域设置(从cppreference复制/改编)将其拆分为token:

struct split_by_equal : std::ctype<char>
{
    static const mask* make_table()
    {
        static std::vector<mask> v(classic_table(), classic_table() + table_size);
        v['='] |=  space;
        return &v[0];
    }
    split_by_equal() : ctype(make_table()){}
};
...
std::stringstream stream("some_tag = some_value");
stream.imbue(std::locale(std::locale::classic(), new split_by_equal));
std::string token;
while(stream>>token)
{
    std::cout<<token<<std::endl;
}

这是有效的,除了我不知道'='是否存在一次,多次或它丢失了。要知道这些信息对于验证输入字符串是非常重要的。

是否有可能使解析停止在字符而不从流中提取它?

PS:我想使用std::locale,因为真正的问题不像只使用'='作为分隔符分割字符串那么简单:)

编辑:

我希望能够以相同的方式解析以下字符串:

"some_tag=some_value"
"some_tag
=
some_value"
"some_tag = some_value"

,并能够报告下一个错误:

"some_tag some_value"
"some_tag == some_value"

您应该使用自定义分隔符参数std::getline,然后使用默认的'n'调用(或多个)。除非你和我们分享整个问题,否则这仍然是最简单、最有效的解决办法。

然后您可以检查您想处理的任何情况。但是处理像这样的东西会很困难:

some_tag
=
some_tag = some_value

这似乎是您可能想要处理的情况,尽管这非常依赖于您想要解析的内容。

Update:我的上一个示例没有考虑到您想要处理的其他情况。我已经测试了它们,它们似乎可以在这个例子中工作:

template<char c>
std::istream& strip_until(std::istream& is)
{
    auto& ctype = std::use_facet<std::ctype<char>>(is.getloc());
    int val = std::char_traits<char>::to_int_type(c);
    bool b;
    while ((b = ctype.is(ctype.space, is.peek())) && is.peek() != val)
        is.ignore();
    if (!b && is.peek() != val)
        is.setstate(std::ios_base::failbit);
    return is;
}
...
while (stream >> token >> strip_until<'='>)
{
    // stream.peek() is '='
}