c++ - 如何根据空格标记特殊字符(< > | & 等)
问题描述
我发现了一个几年前完成的项目,在这里找到了一些简单的命令行解析。虽然我真的很喜欢它的功能,但它不支持解析特殊字符,例如 <、>、& 等。我继续尝试通过添加一些与现有代码相同的条件来添加一些功能来专门解析这些字符用于查找空格、转义字符和引号:
bool _isQuote(char c) {
if (c == '\"')
return true;
else if (c == '\'')
return true;
return false;
}
bool _isEscape(char c) {
if (c == '\\')
return true;
return false;
}
bool _isWhitespace(char c) {
if (c == ' ')
return true;
else if(c == '\t')
return true;
return false;
}
.
.
.
我添加的内容:
bool _isLeftCarrot(char c) {
if (c == '<')
return true;
return false;
}
bool _isRightCarrot(char c) {
if (c == '>')
return true;
return false;
}
其余的特殊字符依此类推。
我还尝试了与方法中现有代码相同的parse
方法:
std::list<string> parse(const std::string& args) {
std::stringstream ain(args); // iterates over the input string
ain >> std::noskipws; // ensures not to skip whitespace
std::list<std::string> oargs; // list of strings where we will store the tokens
std::stringstream currentArg("");
currentArg >> std::noskipws;
// current state
enum State {
InArg, // scanning the string currently
InArgQuote, // scanning the string that started with a quote currently
OutOfArg // not scanning the string currently
};
State currentState = OutOfArg;
char currentQuoteChar = '\0'; // used to differentiate between ' and "
// ex. "sample'text"
char c;
std::stringstream ss;
std::string s;
// iterate character by character through input string
while(!ain.eof() && (ain >> c)) {
// if current character is a quote
if(_isQuote(c)) {
switch(currentState) {
case OutOfArg:
currentArg.str(std::string());
case InArg:
currentState = InArgQuote;
currentQuoteChar = c;
break;
case InArgQuote:
if (c == currentQuoteChar)
currentState = InArg;
else
currentArg << c;
break;
}
}
// if current character is whitespace
else if (_isWhitespace(c)) {
switch(currentState) {
case InArg:
oargs.push_back(currentArg.str());
currentState = OutOfArg;
break;
case InArgQuote:
currentArg << c;
break;
case OutOfArg:
// nothing
break;
}
}
// if current character is escape character
else if (_isEscape(c)) {
switch(currentState) {
case OutOfArg:
currentArg.str(std::string());
currentState = InArg;
case InArg:
case InArgQuote:
if (ain.eof())
{
currentArg << c;
throw(std::runtime_error("Found Escape Character at end of file."));
}
else {
char c1 = c;
ain >> c;
if (c != '\"')
currentArg << c1;
ain.unget();
ain >> c;
currentArg << c;
}
break;
}
}
我在parse
方法中添加的内容:
// if current character is left carrot (<)
else if(_isLeftCarrot(c)) {
// convert from char to string and push onto list
ss << c;
ss >> s;
oargs.push_back(s);
}
// if current character is right carrot (>)
else if(_isRightCarrot(c)) {
ss << c;
ss >> s;
oargs.push_back(s);
}
.
.
.
else {
switch(currentState) {
case InArg:
case InArgQuote:
currentArg << c;
break;
case OutOfArg:
currentArg.str(std::string());
currentArg << c;
currentState = InArg;
break;
}
}
}
if (currentState == InArg) {
oargs.push_back(currentArg.str());
s.clear();
}
else if (currentState == InArgQuote)
throw(std::runtime_error("Starting quote has no ending quote."));
return oargs;
}
parse
将返回令牌字符串列表。
但是,当特殊字符附加到输入的末尾时,我遇到了特定测试用例的问题。例如,输入
foo-bar&
将返回此列表:[{&},{foo-bar}]
而不是我想要的:[{foo-bar},{&}]
我正在努力解决这个问题。我是 C++ 新手,所以任何建议以及一些解释都会有很大帮助。
解决方案
当您处理其中一个字符时,您需要执行与原始代码遇到空格时相同的操作。您需要查看currentState
,然后如果您在其中一个参数中,则保存当前参数(并重置它,因为您不再在一个参数中)。
推荐阅读
- c++ - LLVM:访问函数中的数组参数
- makefile - 使用 makefile 自动创建目录
- javascript - react-native CLI 应该是本地模块还是全局模块?
- c - task_struct -> parent 总是指向根进程而不是实际的父进程
- spring-security-oauth2 - Zuul 网关未携带授权标头
- php - 如何在创建方法 laravel6 后重定向用户?
- batch-file - 批处理文件findstr,如何?
- html - How to merge two forms into one?
- c# - 为什么 SQL Server XML 数据类型会在插入和检索时更改数字签名块中特定属性的顺序?
- c# - Swagger C# 枚举生成 - 基础 int 值与原始枚举不匹配