使用 javascript regex 列出 C++ 中函数的参数

Xel*_*tor 2 javascript c++ regex

我正在使用 javascript 来解析用 doxygen 生成的文档。

我想匹配的函数可能具有以下签名:
funcName (type1 * param1, const myNamespace::type2 param2, myNamespace::type3 param3)

参数的数量可能会有所不同,我想得到以下输出(或类似的东西):
[type1, const myNamespace::type2, myNamespace::type3]

注意:我不想知道它是指针还是引用

到目前为止,这是我尝试过的:

var signature = "funcName (type1 * param1, const myNamespace::type2 param2, myNamespace::type3 param3)";
/(?:.*?)\((?:((?:const\s)?(?:\w+\:\:)?\w+)(?:.*?,\s)?)+/g.exec(signature);
Run Code Online (Sandbox Code Playgroud)

但这只给了我函数中的最后一个类型,或者更准确地说:
["funcName (type1 * param1, const myNamespace::type2 param2, myNamespace::type3", "myNamespace::type3"]

我相信我对非贪婪运算符和非捕获组的广泛使用可能是问题的根源,但我仍然无法解决那个问题......

注意:选项的使用/g似乎没有改变任何东西

Luc*_*ski 5

隔离签名后:

var signature = "funcName (type1 * param1, const myNamespace::type2 param2, myNamespace::type3 param3)";
Run Code Online (Sandbox Code Playgroud)

以下为您提供参数:

var parameters = /\((.*)\)/.exec(signature)[1];
Run Code Online (Sandbox Code Playgroud)

现在,在一般情况下,您不能只是.split(",")它们,因为例如模板类型std::map<int, std::string>

如果你说没有这样的模板类型,那么很简单:

var paramTypes = parameters.split(/\s*,\s*/).map(function(i) {
    return i.replace(/\s*[*&]*\s*\w+$/, "");
});
Run Code Online (Sandbox Code Playgroud)

结果:

["type1", "const myNamespace::type2", "myNamespace::type3"]
Run Code Online (Sandbox Code Playgroud)

让我们\s*[*&]*\s*\w+$从最后看一下正则表达式:

  • $ 确保我们在最后
  • \w+ 匹配参数名称
  • [*&]* 匹配您想要去除的指针和引用限定符
  • \s* 匹配之间可能的空格

这个匹配被一个空字符串替换,所以只剩下类型名称。


现在,为了好玩,让我们考虑一个令人讨厌的案例:

var signature = "funcName (int param1, const std::map<int, std::string>& param2, std::map<int, std::map<int, double>>& param3)";
Run Code Online (Sandbox Code Playgroud)

这仍然成立:

var parameters = /\((.*)\)/.exec(signature)[1];
Run Code Online (Sandbox Code Playgroud)

剩下的,我们需要一个状态机,它真的是一个非常基本的解析器:

function getArgTypes(signature) {
    var parameters = /\((.*)\)/.exec(signature)[1],
        result = [],
        level = 0,
        re = /[^<>,]+|./g,
        match,
        currentParam = "";

    while (match = re.exec(parameters)) {
        currentParam += match[0];

        switch (match[0]) {
            case "<":
                ++level;
                break;

            case ">":
                --level;
                break;

            case ",":
                if (!level) {
                    result.push(currentParam.replace(/\s*[*&]*\s*\w+\s*,$/, "").trim());
                    currentParam = "";
                }
                break;
        }
    }

    currentParam = currentParam.trim();

    if (currentParam)
        result.push(currentParam.replace(/\s*[*&]*\s*\w+\s*$/, ""));

    return result;
}
Run Code Online (Sandbox Code Playgroud)

结果:

["int", "const std::map<int, std::string>", "std::map<int, std::map<int, double>>"]
Run Code Online (Sandbox Code Playgroud)

也没有那么复杂:-)

[^<>,]+|.正则表达式进行符号化,这意味着它的目标是将文本的相关位分成令牌。请注意,在这种特殊情况下,这.实际上是一种简写[<>,]

对于这个例子,我们只对<,>,令牌感兴趣。其余的可以保持粘合在一起(std::map例如,我们可以使用它,无需std :: map像编译器那样将其分开。

这应该给我们以下令牌:

int param1 , const std::map < int , std::string > & param2 , std::map < int , std::map < int , double > > & param3

现在,处理这只是跟踪嵌套级别的问题。