从 class 文件中提取函数

Extract functions from class file

我正在使用正则表达式从 Javascript 中的 AS3 class 文件中提取函数。 但是我对其中有内部括号的函数有疑问(比如内部 if 或其他)。

我看到我可以使用 (?<body>{(?:[^{}]+|(?-1))*+}) 递归地执行此操作,但这不适用于 Javascript,因为不支持递归 (?-1)

我想知道是否有人可以帮我想出另一种解决方案。 这是我的 regex101 测试 = https://regex101.com/r/eE6mX3/1

\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)

感谢所有能帮助我的人。

警告!您继续阅读需要您自担风险!前面的正则表达式真的很丑!!!

(这个是我最初开始的答案,不应该当真。但是背后有很多工作,所以我还是发布了。我的另一个答案应该是你想要的。)


现在...这在一定程度上是可能的——如果嵌套的层数有限,就可以做到。

(我应该指出,我没有使用 AS3 的经验,并且无法将您在 regex101 中的示例与我在 google 上搜索到的内容完全联系起来。)

假设它是 普通 JS 函数的主体,您不想获取此解决方案应该(可以)为您完成。


嵌套

使用 {[^{}]*} 可以轻松匹配内部范围。这匹配两个周围的大括号和它们之间的任何东西([^{}]* 是一个否定字符 class 匹配任何字符 {} - * 表示 任意次数 )。现场示例:

var re = /{[^{}]*}/,
    str = 'one { two { three { four { five } six } seven } eight } nine';
    
    document.write(str.match( re ));

现在,如果我们需要匹配嵌套级别,只需将级别添加到正则表达式即可轻松完成,例如 {[^{}]*{[^{}]*}[^{}]*}。现场示例:

var re = /{[^{}]*{[^{}]*}[^{}]*}/,
    str = 'one { two { three { four { five } six } seven } eight } nine';
    
    document.write(str.match( re ));

甚至四级 - 没问题:{[^{}]*{[^{}]*{[^{}]*{[^{}]*}[^{}]*}[^{}]*}[^{}]*}。现场示例:

var re = /{[^{}]*{[^{}]*{[^{}]*{[^{}]*}[^{}]*}[^{}]*}[^{}]*}/,
    str = 'one { two { three { four { five } six } seven } eight } nine';
    
    document.write(str.match( re ));

当然,你可以走得更远,但开始(?)看起来很恶心。


字符串和注释

现在您可以问自己 - "What about strings and comments?"(如 Wiktor 所述)。好吧,有一个解决方案。

如果我们使用字符串 {one /* two } */ three ' { four }' "} five {" } // {six}(表示带有注释的 JS 代码行),我们可以轻松地自行匹配单独的 部分

  • '(?:\'|[^'])*' 匹配单引号字符串(允许转义单引号)。
  • "(?:\"|[^"])*" 匹配双引号字符串(允许转义双引号)。
  • \/\*(?:[^*]*)*?\*\/ 匹配 /* abc */ 风格的注释(可能是多行)。
  • \/\/.* 匹配 // abc(行尾)样式注释

将这些加入交替匹配所有这些 - 此处说明:

var re = /'(?:\'|[^'])*'|"(?:\"|[^"])*"|\/\*(?:[^*]*)*?\*\/|\/\/.*/g,
    str = '{one /* two } */ three \'{ four }\' "} five {" } // {six}';
    
    document.write(str.match( re ).join('<br/>'));

首先是注释 /* two } */,然后是字符串 ' { four }'"} five {",最后是 // {six} 评论。


综合起来

从匹配 string/comment 部分开始,我们可以避免在搜索匹配对时包含 不需要的 大括号。我们还将包含一个字符 class,它由所有 合法 Javascript 字符(white-space、单词字符、运算符、标点符号等组成) 交替。

那么我们需要得到内部作用域:

{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*}

实例:

var re = /{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*}/,
    code = '// Example code\nfunction(a,b,c) {\n\t// Return sum of all arguments\n\treturn a+b+c;\n\t// Ignore this: }\n}\n';
    
document.write('<span style="background-color:lightblue;">ORIGINAL CODE:<br/></span>');
document.write(code.replace(/\n/g, '<br/>'));

document.write('<span style="background-color:lightblue;">INNER SCOPE:<br/></span>');
document.write(code.match(re)[0].replace(/\n/g, '<br/>'));

将其与上面解释的嵌套逻辑相结合,我们将拥有(真正 复杂的)正则表达式,它应该可以解决问题,但具有前面所述的限制。 (多级嵌套可能会导致超时)。

(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*([^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*([^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*([^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?

(我的天啊!!!我创造了一个怪物!)

var re = /{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*(?:{(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*})?(?:(?:'(?:\'|[^'])*?'|"(?:\"|[^"])*?"|\/\*(?:[^*]*)*?\*\/|\/\/.*)|[\s\w-+\/*.=,();|&[\]:])*}/g,
    unnecessary_complex_code = "var str='123';\n\nfunction /* 123 * 4 * / */ test(\n// qwe\nparam // qwe\n, rapam\n) // \n{\n\ndocument /* qwe*/ . // write\nwrite ( /*\ntest\n*/ test(123) // );\n);\n\n if(param===rapam) {\n  if( false ) {\n   // Another nested level\n   var another_level = {\n    test: { result: true  }\n   };\n  }\n  return // 'FALSE';\n   'TRUE;\n } else return /* 'TRUE';\n */ 'FALSE'\n;\n  /*\n}\n*/\n}\n";
    
    console.log('Code used:');
    console.log(unnecessary_complex_code);
    console.log('Result:');
    console.log(unnecessary_complex_code.match(re));

这可能比您想象的要简单,并且不需要任何正则表达式 解析;)

在解释之前先展示一个例子更容易:

// This is an example of how a function may look

function Demo(first, second, third) {
  // Concatenate the first and second if third is undefined
  if(!third) { // This is to illustrate that a { doesn't cause any problem
    return first + ' - ' + second;
  }
  if(third==='first') { /*
    No problem with } this either
    */ return first;
  }
  if(third==='second') {
    return second;
  }
  else {
    if(third==='first and second') {
      return first + ' and ' + second;
    }
  }
}

// Now show what the function returns when invoked
console.log('The function returns:\n' + Demo('one', 'two'));

// And now - the magic: show the function definition
console.log('The function definition is:\n' + Demo);
span.result {
  background-color: lightblue;
}
span.definition {
  background-color: wheat;
}

在没有 () 的情况下访问函数将 return 函数定义而不是函数的结果。