使用C#从JavaScript文件中获取函数名称和正文代码

时间:2016-09-21 09:03:01

标签: javascript c#

我需要从javascript文件中获取特定函数及其正文作为文本,并使用C#将该函数打印为输出。我需要将函数名和js文件作为输入参数。我尝试使用正则表达式但无法达到预期的效果。这是正则表达式的代码。

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

我还有其他办法吗?

1 个答案:

答案 0 :(得分:0)

这个答案基于您在注释中提供的假设,即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();
}

Demo