通过 UglifyJS 枚举正则表达式
Enumerate regular expressions via 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'
}
我需要弄清楚如何从解析的结构中提取所有此类对象,以便我可以编译位置索引列表。
由于还没有人回答,我想出了一个可行的 head-on 解决方案,尽管可能不是最好的解决方案。
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;
}
我不喜欢这种方法的地方:
我将它用于一个巨大的 30,000 行 JavaScript 文件,该文件在 240 毫秒内被 UglifyJS 解析,然后我的算法又花费了 430 毫秒来枚举正则表达式。这看起来效率很低。
我必须用属性修改原始对象 used
因为解析的结构使用相互引用,否则会导致无限循环和运行调用堆栈。虽然我不是很担心,因为我没有将解析的数据用于其他任何事情。
如果您知道更好的方法 - 请将其投入使用!在这一点上,我最感兴趣的是提高我的枚举的性能,与实际的解析相比,它目前相当慢。
我发现这个最终有用 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;
}
这个东西不仅更短而且工作原理相同,而且它的处理速度几乎是瞬间的,在10ms以内,这让之前的结果(430ms)相形见绌。
这就是我要找的结果! :)
更新: 最后,我发现对于这个特定任务 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;
}
我有一些 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'
}
我需要弄清楚如何从解析的结构中提取所有此类对象,以便我可以编译位置索引列表。
由于还没有人回答,我想出了一个可行的 head-on 解决方案,尽管可能不是最好的解决方案。
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;
}
我不喜欢这种方法的地方:
我将它用于一个巨大的 30,000 行 JavaScript 文件,该文件在 240 毫秒内被 UglifyJS 解析,然后我的算法又花费了 430 毫秒来枚举正则表达式。这看起来效率很低。
我必须用属性修改原始对象
used
因为解析的结构使用相互引用,否则会导致无限循环和运行调用堆栈。虽然我不是很担心,因为我没有将解析的数据用于其他任何事情。
如果您知道更好的方法 - 请将其投入使用!在这一点上,我最感兴趣的是提高我的枚举的性能,与实际的解析相比,它目前相当慢。
我发现这个最终有用 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;
}
这个东西不仅更短而且工作原理相同,而且它的处理速度几乎是瞬间的,在10ms以内,这让之前的结果(430ms)相形见绌。
这就是我要找的结果! :)
更新: 最后,我发现对于这个特定任务 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;
}