简单(大多数)变量解析器

时间:2011-04-04 02:30:04

标签: c++ string-parsing

在我的一个项目中,我需要能够提供一个非常简单的变量查找和替换解析器(主要用于路径)。变量主要在启动时使用,偶尔用于访问文件(不是程序的主要功能,只是加载资源),因此解析器不需要高性能。但是,我更希望它是线程安全的。

解析器需要能够存储一组变量(此时为map<string, string>),并且能够用字符串中的相应值替换标记。变量值可能包含其他变量,这些变量将在使用变量时解析(添加时,因为变量可能会随着时间的推移而添加)。

当前的变量语法类似于:

$basepath$/resources/file.txt
/$drive$/$folder$/path/file

我当前的解析器使用一对stringstream s(“输出”和“varname”),写入“输出”流,直到找到第一个$,“varname”流直到第二个$,然后查找变量(使用varname.str()的内容)。即使在对变量值进行递归时,它也非常简单并且运行良好。

String Parse(String input)
{
    stringstream output, varname;
    bool dest = false;
    size_t total = input.length();
    size_t pos = 0;
    while ( pos < total )
    {
        char inchar = input[pos];
        if ( inchar != '$' )
        {
            if ( dest ) output << inchar;
            else varname << inchar;
        } else {
            // Is a varname start/end
            if ( !dest )
            {
                varname.clear();
                dest = true;
            } else {
                // Is an end
                Variable = mVariables.find(varname.str());
                output << Parse(Variable.value());
                dest = false;
            }
        }

        ++pos;
    }

    return output.str();
}

(错误检查等删除)

然而,当我尝试将它应用于我想要的语法时,该方法失败了。我想要类似于Visual Studio用于项目变量的东西:

$(basepath)/resources/file.txt
/$(drive)/$(folder)/path/file

我也希望能够做到:

$(base$(path))/subdir/file

在变量名中递归会让我陷入困境,我不确定最佳方法。

目前,我有两个可能的概念:

迭代输入字符串,直到我找到$,寻找一个(作为下一个字符,然后找到匹配)(计数水平进出,直到达到正确的关闭paran)。发送该位以进行解析,然后使用返回的值作为变量名称。然而,这看起来很麻烦并导致大量复制。

第二个概念是使用char *,或者char * &,并向前移动直到我达到终止空值。在解析变量名时,解析器函数可以在对自身的递归调用中使用指针。我不确定如何最好地实现这种技术,除了让每个调用跟踪它被解析出的名称,并附加它所做的任何调用的返回值。

该项目只需要在VS2010中编译,因此STL流和字符串,C ++ 0x支持的位以及Microsoft特有的功能都是公平的游戏(如果这些需求发生变化,通用解决方案更可取,但它不是在这一点上是必要的)。但是,使用其他库并不好,尤其不是Boost。

我的想法似乎都比他们需要的更复杂和更麻烦,所以我正在寻找一种很好的处理方式。讨论如何做到最好的代码,想法或文件都非常受欢迎。

1 个答案:

答案 0 :(得分:3)

简单的解决方案是在字符串中搜索第一个')',然后向后移动以查看是否有一个标识符,前面是“$(”。如果是,请替换它并重新开始扫描。如果找不到“$(”标识符,然后找到下一个')' - 当没有一个你完成时。

要解释:通过搜索),您可以确定您正在为替换找到完整的标识符,然后该标识符可以为后续替换中使用的其他标识符做出贡献。

实施例

Had a great time on $($(day)$(month)), did you?

Dictionary: "day" -> "1", "month" -> "April", "1April" -> "April Fools Day"

Had a great time on $($(day)$(month)), did you?
                           ^ find this
Had a great time on $($(day)$(month)), did you?
                      ^^^^^^ back up to match this complete substitution
Had a great time on $(1$(month)), did you?
                      ^ substitution made, restart entire process...
Had a great time on $(1$(month)), did you?
                              ^ find this
etc.