【问题标题】:Fetching function name and body code from JavaScript file using C#使用 C# 从 JavaScript 文件中获取函数名称和主体代码
【发布时间】:2016-09-21 09:03:01
【问题描述】:

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

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

有没有其他方法可以做到这一点?

【问题讨论】:

  • 我认为您会发现 javascript 不够常规。如果不跟踪打开和关闭括号的数量,我想不出一种方法来做到这一点,但是如果不匹配的 } 出现在字符串或 javascript 正则表达式中,您还需要考虑。除非您愿意对该功能做出大量假设,否则您可能应该查看existing javascript parsers for .net
  • 定义:couldnt achieved the desired result.
  • 你需要支持var functionName = function(x) { ... }这样的功能吗? window['function' + name] = function(x) { ... }呢?
  • 更不用说(function(x) { ... })("foo") - 即,IIFE
  • 好吧 - var myFunc = (function(x){ return function() { ... })("foo"); 是一个命名函数 myFunc 但你不会用上面的正则表达式找到它;)

标签: javascript c#


【解决方案1】:

此答案基于您在 cmets 中提供的假设,即 C# 函数只需要查找函数声明,而不需要任何形式的函数表达式。

正如我在 cmets 中指出的那样,javascript 过于复杂,无法用正则表达式有效地表达。知道你已经到达函数末尾的唯一方法是当括号全部匹配时,你仍然需要考虑转义字符、cmets 和字符串。

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

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

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

这应该会让您走得更远,尽管我很想知道人们可以在 cmets 中提出哪些例外:

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

【讨论】:

  • 感谢代码,一直在尝试获取一些解决方案来解析 js 文件并获取所有条目,但是您的消息是我在整个网络中找到的唯一解决方案,很奇怪,但再次感谢。跨度>
猜你喜欢
  • 2014-04-09
  • 2017-09-12
  • 2013-05-26
  • 1970-01-01
  • 2012-10-18
  • 2017-04-01
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多