通过UglifyJS枚举正则表达式

时间:2015-12-30 07:05:07

标签: javascript uglifyjs

我有一些JavaScript代码,我需要从中找到每个文字正则表达式的起始和结束索引。

如何从UglifyJS中提取此类信息?

var uglify = require('uglify-js');
var code = "func(1/2, /hello/);";
var parsed = uglify.parse(code);

我进入变量parsed的结构非常复杂。而我所需要的只是每个字面正则表达式[{startIdx, endIdx}, {startIdx, endIdx}]的数组。

P.S。如果有人认为可以通过比通过UglifyJS更好的方式完成同样的任务,欢迎提出建议!

更新

我知道如果我深入研究解析后的结构,那么对于每个正则表达式我都可以找到对象:

AST_Token {
     raw: '/hello/',
     file: null,
     comments_before: [],
     nlb: false,
     endpos: 17,
     endcol: 17,
     endline: 1,
     pos: 10,
     col: 10,
     line: 1,
     value: /hello/,
     type: 'regexp'
}

我需要弄清楚如何从解析的结构中提取所有这些对象,这样我就可以编译位置索引列表。

2 个答案:

答案 0 :(得分:1)

我得到了这个最终有用的link to the UglifyJS author's blog post,它指出了我正确的方向。基于该博客,我能够将我的枚举代码修改为以下内容:

function enumRegEx(parsed) {
    var result = [];
    parsed.walk(new uglify.TreeWalker(function (obj) {
        if (obj instanceof uglify.AST_RegExp) {
            result.push({
                startIdx: obj.end.col,
                endIdx: obj.end.endcol
            });
        }
    }));
    return result;
}

不仅这个东西更短并且工作原理相同,但它的处理速度几乎是瞬间的,在10毫秒内,这使之前的结果(430毫秒)变得羞耻。

现在这就是我要找的结果! :)

更新:最后,我发现对于这个特定任务esprima是一个更好的选择。与UglifyJS不同,它更快,并且具有完整的ES6支持。

通过esprima完成同样的任务,得益于Ariya Hidayat的出色支持:

function parseRegEx(originalCode) {
    var result = [];
    esprima.tokenize(originalCode, {loc: true, range: true}, function (obj) {
        if (obj.type === 'RegularExpression') {
            result.push({
                startIdx: obj.range[0],
                endIdx: obj.range[1]
            });
        }
    });
    return result;
}

正如您所看到的,使用esprima甚至不需要解析代码,而是传入原始代码,而esprima只会标记化,这样会更快。

答案 1 :(得分:0)

由于还没有人回答,我设法提出了一个正常的解决方案,虽然可能不是最好的解决方案。

Public Sub Main()
    Console.WriteLine(HasPointingDevice())
    Console.WriteLine(HasKeyboard())
    Console.ReadKey()
End Sub

我不喜欢这种做法的事情:

  • 我将它用于一个庞大的30,000行JavaScript文件,该文件由UglifyJS在240ms内解析,然后我的算法需要另外430ms才能枚举正则表达式。这似乎效率很低。

  • 我必须使用属性function enumRegEx(parsed) { var result = []; function loop(obj) { if (obj && typeof obj === 'object') { if (obj.used) { return; } else { obj.used = true; } if (obj instanceof Array) { obj.forEach(function (d) { loop(d); }); } else { if (obj instanceof uglify.AST_Node) { for (var v in obj) { loop(obj[v]); } } else { if (obj instanceof uglify.AST_Token) { if (obj.type === 'regexp') { result.push({ startIdx: obj.col, endIdx: obj.endcol }); } } } } } } loop(parsed); return result; } 修改原始对象,因为解析后的结构使用相互引用,否则会导致无限循环并耗尽调用堆栈。虽然我并不那么担心,因为我没有将解析后的数据用于其他任何事情。

如果你知道更好的方法 - 请把它扔进去!在这一点上,我最感兴趣的是提高枚举的性能,与目前实际的解析相比,这个枚举目前相当慢。