使用c#从JavaScript文件中获取函数名和函数体代码

Fetching function name and body code from JavaScript file using C#

本文关键字:函数 函数体 代码 获取 JavaScript 文件 使用      更新时间:2023-09-26

我需要从javascript文件中获取特定的函数和它的主体作为文本,并使用c#打印该函数作为输出。我需要给函数名和js文件作为输入参数。我尝试使用正则表达式,但不能达到预期的结果。以下是正则表达式的代码:

public void getFunction(string jstext, string functionname)
{
    Regex regex = new Regex(@"function's+" + functionname + @"'s*'(.*')'s*'{");
    Match match = regex.Match(jstext);
}

还有别的办法吗?

这个答案是基于你在注释中提供的假设,即c#函数只需要查找函数声明,而不需要任何形式的函数表达式。

正如我在注释中指出的那样,javascript太复杂了,无法用正则表达式有效地表达。要知道已经到达函数的末尾,唯一的方法是当括号全部匹配时,并且在这种情况下,您仍然需要考虑转义字符、注释和字符串。

我能想到的实现这一点的唯一方法是,从函数体的开始,直到括号匹配为止,实际上遍历每个字符,并跟踪出现的任何奇怪的东西。

这样的解决方案永远不会很漂亮。我已经拼凑了一个例子来说明它是如何工作的,但是知道javascript是如何充满小怪癖和陷阱的,我相信这里有许多没有考虑到的极端情况。我也确信它可以做得更整洁一些。

从我的第一个实验,下面应该处理转义字符,多行和单行注释,由",'或'分隔的字符串,以及正则表达式(即由/分隔)。

这应该会让你走得很远,尽管我很想看看人们在注释中能想出什么异常:

private static string GetFunction(string jstext, string functionname) {
    var start = Regex.Match(jstext, @"function's+" + functionname + @"'s*'([^)]*')'s*{");
    if(!start.Success) {
        throw new Exception("Function not found: " + functionname);     
    }
    StringBuilder sb = new StringBuilder(start.Value);
    jstext = jstext.Substring(start.Index + start.Value.Length);
    var brackets = 1;
    var i = 0;
    var delimiters = "`/''"";
    string currentDelimiter = null;
    var isEscape = false;
    var isComment = false;
    var isMultilineComment = false;
    while(brackets > 0 && i < jstext.Length) {
        var c = jstext[i].ToString();
        var wasEscape = isEscape;
        if(isComment || !isEscape)
        {
            if(c == @"'") {
                // Found escape symbol.
                isEscape = true;
            } else if(i > 0 && !isComment && (c == "*" || c == "/") && jstext[i-1] == '/') {
                // Found start of a comment block
                isComment = true;
                isMultilineComment = c == "*";
            } else if(c == "'n" && isComment && !isMultilineComment) {
                // Found termination of singline line comment
                isComment = false;
            } else if(isMultilineComment && c == "/" && jstext[i-1] == '*') {
                // Found termination of multiline comment
                isComment = false;
                isMultilineComment = false;
            } else if(delimiters.Contains(c)) {
                // Found a string or regex delimiter
                currentDelimiter = (currentDelimiter == c) ? null : currentDelimiter ?? c;
            }
            // The current symbol doesn't appear to be commented out, escaped or in a string
            // If it is a bracket, we should treat it as one
            if(currentDelimiter == null && !isComment) {
                if(c == "{") {
                    brackets++;
                }
                if(c == "}") {
                    brackets--;
                }
            }
        }
        sb.Append(c);
        i++;
        if(wasEscape) isEscape = false;
    }

    return sb.ToString();
}
演示