很长一段时间以来,我一直在努力为我的程序创建输入法。
我希望程序接受以下形式的输入:
function entity(number,text,text)
function entity(number)
function entity(int, text, int)
我希望程序根据用户以上面显示的形式输入的命令进行操作。他们选择了这个功能。添加实体例如学生并在括号中填写有关这些实体的数据。现在我要实现的是将此字符串拆分为add / entity的块和括号中的所有值,以便我可以根据它们进行操作。
到目前为止我设法实现的是完全错误的,因为我对整个c ++事情都相当陌生,所以它确实很难在半个时间内完全解决这个问题
string function, entity;
char values[1024];
char command[1024];
cin.getline(command, 1024);
stringstream t;
t << command;
int number[5];
char parameter1[20];
char parameter2[20];
t >> funtion >> entity >> values;
sscanf_s(values, "%s %s %s ", number, _countof(number), parameter1, _countof(parameter1), parameter2, _countof(parameter2));
简单来说,我想从函数实体(参数,参数,参数)剪切字符串/ char(我尝试了两种不同的东西)到我可以在程序中的其他地方使用的小块。需要摆脱括号,逗号并分别取出每个单词。
答案 0 :(得分:0)
您选择的方法非常适合该问题,特别是如果您以后想要向程序添加更多命令表单。
处理这种输入的正确方法是使用诸如GNU Bison之类的解析器生成器编写解析器,但在您的情况下可能过度,需要太多空间来解释,并且需要一些关于语言的知识和语法(在计算机科学意义上)。如果您想了解更多相关信息,请在Google上搜索“GNU Bison”或“解析器生成器”。
更有限但更容易理解的解决方案是使用C ++ 11正则表达式。首先匹配整行以查找函数,实体和参数列表,然后根据实体或函数类型匹配参数列表。代码看起来像这样:
// This regular expression matches one line of input (one command).
// A line has some text starting with a letter (the function name),
// then one or more spaces, another piece of text,
// and then a string of arbitrary characters inside parentheses.
// Parentheses not preceded by \\ denote capture groups.
// Any characters matched by them are later accessible through
// the std::smatch object.
std::regex rx_line("([A-Za-z][A-Za-z0-9]*)\\s+"
"([A-Za-z][A-Za-z0-9]*)\\s*"
"\\((.*)\\)\\s*");
// Retrieve one non-empty line of input, skipping whitespace.
std::string line;
std::getline(std::cin >> std::ws, line);
// Match the line regex to the line, capturing the parts of text which we want.
std::smatch line_match;
if (!std::regex_match(line, line_match, rx_line)) {
// Report error: the command has incorrect format.
}
// Retrieve parts of the input matched by capture groups.
std::string function = line_match[1];
std::string entity = line_match[2];
std::string params = line_match[3];
// Depending on which entity was mentioned in the command,
// match the parameters to a suitable regex.
if (entity == "student") {
// number, then comma, then text in quotes, then comma,
// and finally a number.
std::regex rx_student("([1-9][0-9]*)\\s*,"
"\\s*\"([^\"]*)\"\\s*,"
"\\s*([1-9][0-9]*)");
std::smatch student_match;
if (!std::regex_match(params, student_match, rx_student)) {
// report error
}
// Retrieve parameters from capture groups.
int int1 = std::atoi(student_match[1].str().c_str());
std::string text = student_match[2];
int int2 = std::atoi(student_match[3].str().c_str());
// ...
// do something with the data
// ...
} else if (entity == "account") {
// and so on
} else {
// error - unknown entity
}
参见例如http://www.cplusplus.com/reference/regex/ECMAScript/有关正则表达式语法的说明。
答案 1 :(得分:0)
我认为值得从一开始就开始:虽然它有一个固定大小的缓冲区可以读入,但我认为使用std::string
来捕获每一行更容易。此外,如果读取操作成功,您应该在读取后始终测试。也就是说,我会编写一个外部循环来处理各个行:
for (std::string line; std::getline(std::cin >> std::ws, line); ) {
// process each individual line
}
使用操纵器std::ws
会使循环内部的东西更容易:它会跳过所有空格,例如,一行上的前导空格和空行。也就是说,如果std::getline()
设法读取一行,则已知该行不为空。
根据您撰写的有关您的功能的内容,它们似乎有不同的参数。所以我会创建一个字符串流来处理单个行,将第一个单词作为命令读取,并根据该分割读取更多参数:
std::istringstream sin(line);
std::string command;
if (sin >> command) {
if (command == "add") {
int number;
std::string name;
if (sin >> number >> name) {
entity(number, name);
}
else {
std::cout << "ERROR: failed to read add command from '" << line << "'\n";
}
else if (command == "???") {
// ...
}
else {
std::cout << "ERROR: unrecognized command on line '" << line << "'\n";
}
}
有可能编写一个函数来确定传递给它的函数指针的参数,读取它们并调用函数,但这需要一些高级技术。基于您的问题,提供答案将为您提供一个可能有点过于复杂的解决方案。
答案 2 :(得分:0)
您尝试实现的是解析,而不仅仅是原始拆分。 以下是使用boost::spirit将对您有用的示例。我强烈建议你使用这些工具,因为它可以让你有一点灵活性,因为scanf的原始文件解析不能提供给你。这不是唯一可用的工具,但值得花时间学习它。
所以这里是我的小评论示例,我希望它对您有所帮助:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_as.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
// Parameters can be either string or int
typedef boost::variant<std::string, double> Parameter;
// Here is the function where we read the command and retrieve entity/function
// and parameters
bool read_command(const std::string& str)
{
// Just to ease the parser writing
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
typedef qi::rule<std::string::const_iterator, std::string()> rule;
// Variables where we will store the results
std::string entity;
std::string function;
std::vector<Parameter> arguments;
// An identifier
rule identifier = qi::alpha >> *(qi::alnum | qi::char_("_"));
// A parameter is either a number or an identifier, there is a issue if we
// use "rule" type here, double are not read correctly anymore...
auto parameter = qi::double_ | identifier;
// The whole command
bool r = qi::phrase_parse(str.begin(), str.end(),
( identifier >> identifier >> '(' >> (parameter % ',' ) >> ')' ),
qi::space, entity, function, arguments); // Use qi "magic" to store result
// Print everything
std::cout
<< "Parsing result:" << std::endl
<< " - Entity: " << entity << std::endl
<< " - Function: " << function << std::endl
<< " - " << arguments.size() << " parameter(s): ";
// Use copy to print all the arguments
std::copy(arguments.begin(), arguments.end(),
std::ostream_iterator<Parameter>(std::cout, ", "));
std::cout << std::endl;
return r;
}
int main()
{
std::string str;
// Read the line
while (getline(std::cin, str))
{
// Check that this is a line we do want to parse
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
{
break;
}
// Read the command and output the result
if (read_command(str))
{
std::cout << "Parsing succeeded! " << std::endl;
}
else
{
std::cout << "Parsing failed." << std::endl;
}
}
return 0;
}
输出示例:
$ ./a.exe
test f(1)
Parsing result:
- Entity: test
- Function: f
- 1 parameter(s): 1,
Parsing succeeded!
entity function(1, a, b)
Parsing result:
- Entity: entity
- Function: function
- 3 parameter(s): 1, a, b,
Parsing succeeded!
er1_ ft_(1, r_)
Parsing result:
- Entity: er1_
- Function: ft_
- 2 parameter(s): 1, r_,
Parsing succeeded!