我使用boost::program_options
来解析我的命令行。现在,我通过表示文件的--script
参数添加对批处理执行的支持,包含每行的命令行选项,例如:
--src="\"z:\dev\veds\sqlexpress\Run 1.ved\"" --src-kind=bla --yz
--src=z:\dev\veds\sqlexpress\db.ebf
--src=z:\dev\veds\sqlexpress\db2.mdf
--src=db3
--src="\"z:\dev\veds\sqlite\Run 41 (Run 23).ved\""
--src=z:\dev\veds\sqlite\ws_results_db_2012_01_15_18_37_03.db3
--src=z:\dev\veds\mysql\10.ved
--src=z:\dev\veds\mysql\db
文件中的每一行表示我的工具的单次执行,并列出了此特定执行的命令行选项。
问题是读取脚本文件会产生完整的行,这些行不会分成单独的命令行选项。但是,为了使用argc
,必须有argv
和boost::program_options
,即依赖于某人将命令行分解为不同的选项。
我不能简单地用空格分隔,因为有些值包含空格,因此它们用双引号括起来,甚至是嵌套的双引号。
另一方面,我不希望从OS命令提示符为每组命令行选项运行该工具,因为昂贵的引导程序 - 我首先介绍脚本功能的原因。 / p>
是否有一种简单的方法可以像操作系统一样将行划分为命令行参数?
感谢。
答案 0 :(得分:1)
好的,我知道了。这是我的代码:
string script;
{
ifstream file(scriptPath.c_str());
file.seekg(0, ios::end);
script.resize(file.tellg());
file.seekg(0, ios::beg);
file.read(const_cast<char *>(script.c_str()), script.size());
}
boost::replace_all(script, "\\", "\\\\"); // Escape the backslashes
boost::replace_all(script, "\\\\\"", "\\\""); // Except for those escaping the quotes
boost::trim_right_if(script, is_space_or_zero); // There are extra '\0' in the string, because the file is read as text, but its length was computed as binary
vector<string> lines;
boost::split(lines, script, boost::is_any_of("\n")); // I prefer getting a string line iterator here, the question is how?
escaped_list_separator<char> sep('\\', ' ', '"');
int res = 0;
BOOST_FOREACH (const string& line, lines)
{
// reset the command line variables here, since this is like a new execution
// Tokenize the command line, respecting escapes and quotes
tokenizer<escaped_list_separator<char>> tok(line, sep);
vector<string> args(tok.begin(), tok.end());
po::variables_map vm;
po::store(po::command_line_parser(args).options(options).run(), vm);
res += run(vm);
}
我正在使用http://www.boost.org/doc/libs/1_48_0/libs/tokenizer/打破界限。效果很好。
答案 1 :(得分:0)
Boost文档涵盖Response Files,包括使用它们的简单示例。这将接近你想要的,除了他们还说它“有一些限制”,其中包括解析空间。
他们还有parse_config_file(),它会从文件中加载选项。在这里,你将放弃在文件中使用与命令行相同的语法,并且它们包含的实现只会(轻松地)支持每个程序调用一次“命令调用”。但我打赌你可以看看他们是如何做到的并复制一些代码。如果我是你,我可能会调整它以支持.ini语法,如下所示:
[job1]
src=z:\dev\veds\sqlexpress\Run 1.ved
src-kind=bla
y=
z=
[job2]
src=z:\dev\veds\sqlexpress\db.ebf
[another_job]
src=z:\dev\veds\sqlexpress\db2.mdf
我敢打赌,这不是一项额外的工作,而且它为你所经营的每项工作提供了一个明确的名称。 Boost自己的parse_config_file()使用节名称(括号中)作为选项名称的前缀,但这不是必需的,因此您可以重新调整它们以保持简单的.ini语法。
编辑:你想要更简单的东西吗?好。放弃在文件中使用与引用和空格相同的句法语法的想法。如果必须支持参数中的空格,请在选项之间确定合适的分隔符,如;
。使用std :: string :: find()或Boost Tokenizer将这样的东西转换成argc / argv对应该很容易:
--src=z:\dev\veds\sqlexpress\Run 1.ved; --src-kind=bla; --yz
--src=z:\dev\veds\sqlexpress\db.ebf
--src=z:\dev\veds\sqlexpress\db2.mdf
在;
上拆分以在第一个示例中生成argv [1,2,3],并将程序自己的argv [0]复制到“伪”argv [0],然后使用Boost解析选项
答案 2 :(得分:0)
检查出来:: C ++ Cookbook拆分字符串(方法4.6)
例4-10。拆分分隔的字符串
#include <string>
#include <vector>
#include <functional>
#include <iostream>
using namespace std;
void split(const string& s, char c,
vector<string>& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length( )));
}
}
int main( ) {
vector<string> v;
string s = "Account Name|Address 1|Address 2|City";
split(s, '|', v);
for (int i = 0; i < v.size( ); ++i) {
cout << v[i] << '\n';
}
}
-
template<typename T>
void split(const basic_string<T>& s, T c,
vector<basic_string<T> >& v) {
basic_string<T>::size_type i = 0;
basic_string<T>::size_type j = s.find(c);
while (j != basic_string<T>::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == basic_string<T>::npos)
v.push_back(s.substr(i, s.length( )));
}
}
例4-11。使用Boost
拆分字符串#include <iostream>
#include <string>
#include <list>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
int main( ) {
string s = "one,two,three,four";
list<string> results;
split(results, s, is_any_of(",")); // Note this is boost::split
for (list<string>::const_iterator p = results.begin( );
p != results.end( ); ++p) {
cout << *p << endl;
}
}
-
template<typename Seq,
typename Coll,
typename Pred>
Seq& split(Seq& s, Coll& c, Pred p,
token_compress_mode_type e = token_compress_off);
我不能自由分享文本(非法复制/粘贴书籍),但这些例子非常具有解释性。如果你想看文本,你需要参考这本书。
这两个例子来自
的食谱4.6C ++ Cookbook
Jeff Cogswell,Christopher Diggins,Ryan Stephens,Jonathan Turkanis
出版商:O'Reilly
发布日期:2005年11月
ISBN:0-596-00761-2