C++-如何使用流来解析文件
C++ - How to use a stream to parse a file?
我有一个文件,我需要循环遍历它,分配一个64/128位长的int foo,字符串类型。我该如何使用流将这些行解析为以下变量-我想坚持流语法(ifs>>foo>>类型),但在这种情况下,类型最终将是0/52之后的行的其余部分。。。在这一点上,我只需要得到一个char*并使用strtoull等,那么为什么要首先使用流呢。。。我希望可读代码在char字符串/strttok/strtoull 上没有糟糕的性能
//input file:
0ULL'04001C0180000000000000000EE317BC'
52L'04001C0180000000'
//ouput:
//0 ULL 0x04001C0180000000 0x000000000EE317BC
//52 L 0x04001C0180000000
ifstream ifs("input.data");
int foo;
string type;
unsigned long long ull[2];
Boost Spirit实现
以下是基于强制Boost Spirit(Qi)的实施。为了更好的衡量,包括使用Boost Spirit(因果报应)格式化:
#include <string>
#include <iostream>
#include <fstream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace karma=boost::spirit::karma;
namespace qi =boost::spirit::qi;
static qi::uint_parser<unsigned long long, 16, 16, 16> hex16_p; // parse long hex
static karma::uint_generator<unsigned long long, 16> hex16_f; // format long hex
int main(int argc, char** args)
{
std::ifstream ifs("input.data");
std::string line;
while (std::getline(ifs, line))
{
std::string::iterator begin = line.begin(), end = line.end();
int f0;
std::string f1;
std::vector<unsigned long long> f2;
bool ok = parse(begin, end,
qi::int_ // an integer
>> *qi::alpha // alternatively: *(qi::char_ - ''')
>> ''' >> +hex16_p >> ''' // accepts 'n x 16' hex digits
, f0, f1, f2);
if (ok)
std::cout << "Parsed: " << karma::format(
karma::int_
<< ' ' << karma::string
<< ' ' << ("0x" << hex16_f) % ' '
, f0, f1, f2) << std::endl;
else
std::cerr << "Parse failed: " << line << std::endl;
}
return 0;
}
试运行:
Parsed: 0 ULL 0x4001c0180000000 0xee317bc
Parsed: 52 L 0x4001c0180000000
请参阅下面的调整和样本,了解如何调整的信息,例如十六进制输出
基准
我已经在您提供的100000倍样本输入上对@Cubbi的版本和上述进行了基准测试。这最初给Cubbi的版本带来了一点优势:0.786s
相对于0.823s
。
现在,这当然不是一个公平的比较,因为我的代码每次都在动态构建解析器。这样从循环中取出:
typedef std::string::iterator It;
const static qi::rule<It> parser = qi::int_ >> *qi::alpha >> ''' >> +hex16_p >> ''';
bool ok = parse(begin, end, parser, f0, f1, f2);
Boost Spirit以0.093s
的成绩脱颖而出;已经快了8.5倍,即使每次迭代仍在构建因果报应格式化程序。
两个版本的输出格式都被注释掉了,Boost Spirit的速度快了11倍
调整,采样
注意如何轻松调整:
// >> ''' >> +hex16_p >> ''' // accepts 'n x 16' hex digits
>> ''' >> qi::repeat(1,2)[ hex16_p ] >> ''' // accept 16 or 32 digits
或者像输入一样格式化十六进制输出:
// ("0x" << hex16_f) % ' '
karma::right_align(16, '0')[ karma::upper [ hex16_f ] ] % ""
更改的样本输出:
0ULL'04001C0180000000000000000EE317BC'
Parsed: 0 ULL 04001C0180000000000000000EE317BC
52L'04001C0180000000'
Parsed: 52 L 04001C0180000000
HTH
对于更复杂的解析器(如boost.spirit.)来说,这是一项相当琐碎的任务
要使用仅标准C++流来解决此问题,您需要
- a) 将
'
视为空白 - b) 对字符串"04001C0180000000000000000000EE317BC"进行额外的遍历,该字符串的值之间没有分隔符
借用Jerry Coffin的示例方面代码
#include <iostream>
#include <fstream>
#include <locale>
#include <vector>
#include <sstream>
#include <iomanip>
struct tick_is_space : std::ctype<char> {
tick_is_space() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(table_size, std::ctype_base::mask());
rc['n'] = std::ctype_base::space;
rc['''] = std::ctype_base::space;
return &rc[0];
}
};
int main()
{
std::ifstream ifs("input.data");
ifs.imbue(std::locale(std::locale(), new tick_is_space()));
int foo;
std::string type, ullstr;
while( ifs >> foo >> type >> ullstr)
{
std::vector<unsigned long long> ull;
while(ullstr.size() >= 16) // sizeof(unsigned long long)*2
{
std::istringstream is(ullstr.substr(0, 16));
unsigned long long tmp;
is >> std::hex >> tmp;
ull.push_back(tmp);
ullstr.erase(0, 16);
}
std::cout << std::dec << foo << " " << type << " "
<< std::hex << std::showbase;
for(size_t p=0; p<ull.size(); ++p)
std::cout << std::setw(16) << std::setfill('0') << ull[p] << ' ';
std::cout << 'n';
}
}
测试:https://ideone.com/lRBTq
相关文章:
- 有充分的理由在h文件中使用include保护而不是cpp文件吗
- 如何在其他文件中使用函数
- 在实现文件中使用头文件的通用 lambda
- 将 getline() 与文件一起使用
- 在头文件和 cpp 文件中使用一次 #pragma 时出现结构重定义错误
- 定义C++新的环境变量并在 bat 文件中使用它
- 如何在另一个 CPP 文件中使用一个 cpp 文件中的函数?
- 在 embarcadero / RAD 工作室中的 .dfm 文件中使用常量
- 声明要在 qml 和 cpp 文件中使用的全局字符串
- 如何在 linux 可执行文件中使用静态库
- 在C++的头文件中使用常量并在程序中询问其地址的任何潜在危险
- 使用 libssh 从 SFTP 服务器下载文件并使用 C++ 将其写入 ofstream?
- CocoaPod - 在头文件中使用 C++ 时出现 Podspec 检查错误
- 链接器输入文件未使用,因为链接未完成,我无法获得.o
- 使用个人C++库编译代码时,与头文件一起使用时会中断
- 如何为文件路径使用变量?
- 没有头文件如何使用c ++调用其他模块中的函数?
- 在带有类型保护的模板文件中使用前向声明
- 无法使包含.hpp文件与其中的2个文件一起使用
- 文件删除(使用取消链接)与释放所有磁盘空间之间的延迟