4

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

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

当前的变量语法看起来像:

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

我当前的解析器使用一对stringstreams(“output”和“varname”),写入“output”流直到找到第一个 $,“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

递归变量名让我陷入困境,我不确定最好的方法。

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

遍历输入字符串,直到找到 $,查找 ( 作为下一个字符,然后找到匹配的 )(计数进出级别,直到达到正确的关闭参数)。发送该位进行解析,然后使用返回的值作为变量名。但是,这似乎会很混乱并导致大量复制。

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

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

我的两个想法似乎都比需要的更复杂和混乱,所以我正在寻找一种干净的方式来处理这个问题。非常欢迎讨论如何最好地做到这一点的代码、想法或文档。

4

1 回答 1

3

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

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

例子

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.
于 2011-04-04T02:45:03.643 回答