我有一个这样的字符串:
"CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567"
现在 ": "
将键与值分开,而 \n
分开对。我想将键值对添加到 C++ 中的映射中。
考虑到优化,有没有任何有效的方法可以做到这一点?
原文由 Viking 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有一个这样的字符串:
"CA: ABCD\nCB: ABFG\nCC: AFBV\nCD: 4567"
现在 ": "
将键与值分开,而 \n
分开对。我想将键值对添加到 C++ 中的映射中。
考虑到优化,有没有任何有效的方法可以做到这一点?
原文由 Viking 发布,翻译遵循 CC BY-SA 4.0 许可协议
这种格式称为“标签值”。
在行业中使用这种编码的最性能关键的地方可能是金融 FIX 协议( =
用于键值分隔符,以及 '\001'
作为条目分隔符)。因此,如果您使用的是 x86 硬件,那么您最好的选择是搜索“SSE4 FIX 协议解析器 github”并重用 HFT 商店的开源发现。
如果您仍然想将矢量化部分委托给编译器并且可以节省几纳秒以提高可读性,那么最优雅的解决方案是将结果存储在 std::string
(data) + boost::flat_map<boost::string_ref, boost::string_ref>
(看法)。解析是一个口味问题,while-loop 或 strtok 对编译器来说是最容易解析的。基于 Boost-spirit 的解析器对于人类(熟悉 boost-spirit)来说是最容易阅读的。
基于 C++ for 循环的解决方案
#include <boost/container/flat_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/iterator_range_io.hpp>
#include <iostream>
// g++ -std=c++1z ~/aaa.cc
int main()
{
using range_t = boost::iterator_range<std::string::const_iterator>;
using map_t = boost::container::flat_map<range_t, range_t>;
char const sep = ':';
char const dlm = '\n';
// this part can be reused for parsing multiple records
map_t result;
result.reserve(1024);
std::string const input {"hello:world\n bye: world"};
// this part is per-line/per-record
result.clear();
for (auto _beg = begin(input), _end = end(input), it = _beg; it != _end;)
{
auto sep_it = std::find(it, _end, sep);
if (sep_it != _end)
{
auto dlm_it = std::find(sep_it + 1, _end, dlm);
result.emplace(range_t {it, sep_it}, range_t {sep_it + 1, dlm_it});
it = dlm_it + (dlm_it != _end);
}
else throw std::runtime_error("cannot parse");
}
for (auto& x: result)
std::cout << x.first << " => " << x.second << '\n';
return 0;
}
原文由 bobah 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答1.4k 阅读✓ 已解决
1 回答1.1k 阅读✓ 已解决
4 回答913 阅读
1 回答983 阅读
1 回答1k 阅读
1 回答772 阅读
1 回答874 阅读
好吧,我这里有两种方法。第一个是我一直使用的简单、明显的方法(性能很少成为问题)。第二种方法可能更有效,但我没有做任何正式的计时。
在我的测试中,第二种方法快了大约 3 倍。
输出: