我有一个很大的有效JavaScript文件(utf-8),我需要从中自动提取所有文本字符串。
为简单起见,该文件中不包含任何注释块,只包含有效的ES6 JavaScript代码。
一旦我发现'
或"
或`的出现,我应该扫描文本块的末尾,是我被卡住的地方,考虑到所有可能的变化,例如"'"
,'"'
," \'",' \"','"
,`\ ``等等。
是否有已知和/或可重用的算法来检测有效ES6 JavaScript文本块的结尾?
UPDATE-1:我的JavaScript文件不是很大,我还必须以块的形式处理它,因此Regex绝对不可用。我不想让我的问题复杂化,提到联合代码块,我会自己解决这个问题,如果我有一个算法可以处理内存中的单个代码。
UPDATE-2:我最初开始工作了,感谢这里提出的许多建议,但是由于正则表达式,我再次陷入困境。
正则表达式的示例,它破坏了目前建议的任何文本检测技术:
/'/
/"/
/\`/
仔细研究了这个问题后,通过阅读:How does JavaScript detect regular expressions?,我担心在JavaScript中检测正则表达式是一个全新的球类游戏,值得一个单独的问题,否则它会变得太复杂。但是,如果有人能指出我在这个问题上的正确方向,我非常感激......
UPDATE-3:经过大量研究后,我遗憾地发现我无法提出一种在我的情况下可行的算法,因为正则表达式的存在使得任务比最初的复杂得多思想。根据以下内容:When parsing Javascript, what determines the meaning of a slash?,确定JavaScript中正则表达式的开头和结尾是最复杂和最复杂的任务之一。没有它我们无法弄清楚符号'
,'"'并且`正在打开一个文本块或它们是否在正则表达式中。
答案 0 :(得分:3)
解析JavaScript的唯一方法是使用JavaScript解析器。即使你能够使用正则表达式,但在一天结束时,它们还不足以完成你在这里尝试做的事情。
您可以使用几种现有解析器中的一种,它们非常易于使用,或者您可以编写自己的解析器,简化以专注于字符串提取问题。我很难想象你想编写自己的解析器,甚至是简化的解析器。你将花费更多的时间来编写和维护它,而不是你想象的那样。
例如,现有的解析器将处理类似下面的内容而不会出汗。
`foo${"bar"+`baz`}`
解析器的明显候选者是esprima和babel。
顺便说一下,一旦你提取出来,你打算用这些字符串做什么?
答案 1 :(得分:0)
如果您只需要一个近似答案,或者您想要获得与源代码中出现的字符串文字完全相同的字符串文字,那么正则表达式就可以完成这项工作。
给定字符串文字"\n"
,您是否期望包含换行符的单字符字符串或两个字符反斜杠和n?
\x40
和\u2026
,因此即使在这种情况下,您也应该复制现有JavaScript词法分析器中的代码。请参阅https://github.com/douglascrockford/JSLint/blob/master/jslint.js,功能tokenize
。
答案 2 :(得分:-1)
尝试以下代码:
txt = "var z,b \n;z=10;\n b='321`1123`321321';\n c='321`321`312`3123`';"
function fetchStrings(txt, breaker){
var result = [];
for (var i=0; i < txt.length; i++){
// Define possible string starts characters
if ((txt[i] == "'")||(txt[i] == "`")){
// Get our text string;
textString = txt.slice(i+1, i + 1 + txt.slice(i+1).indexOf(txt[i]));
result.push(textString)
// Jump to end of fetched string;
i = i + textString.length + 1;
}
}
return result;
};
console.log(fetchStrings(txt));
答案 3 :(得分:-1)
我可以让你自己测试一下吗?我相信你应该能够在经过一些调整后使用这个解决方案(例如,将每个新块重置为0可能是一个很好的起点)。我可以继续处理您的问题,但我希望您告诉我,我是否正朝着正确的方向前进: - )
此代码使用递归来跟踪当前状态(代码,字符串,注释或正则表达式)。我不熟悉处理大文件,因此我担心它会导致堆栈溢出。作为一种解决方法,您可以将状态保存在全局变量中,并以迭代方式执行所有这些操作。
var strings = [];
code(document.getElementsByTagName('script')[0].textContent, 0);
document.write('<pre>' + JSON.stringify(strings, 0, 2) + '</pre>');
function code (text, i) {
if (i < text.length) {
var c = text.charAt(i);
if (/`|'|"/.test(c)) {
strings.push('');
string(text, i + 1, text.charAt(i));
} else if (c == '/') {
slash(text, i + 1);
} else {
code(text, i + 1);
}
}
}
function string (text, i, quote) {
if (i < text.length) {
var step, c = text.charAt(i);
if (c == quote) {
code(text, i + 1);
} else {
step = c == '\\' ? 2 : 1;
strings[strings.length - 1] += text.substr(i, step);
string(text, i + step, quote);
}
}
}
function slash (text, i) {
if (i < text.length) {
var c = text.charAt(i);
if (c == '/') {
singlelinecomment(text, i + 1);
} else if (c == '*') {
multilinecomment(text, i + 1, '');
} else {
regex(text, i + 1);
}
}
}
function singlelinecomment (text, i) {
if (i < text.length) {
var c = text.charAt(i);
if (c == '\n') {
code(text, i + 1);
} else {
singlelinecomment(text, i + 1);
}
}
}
function multilinecomment (text, i, prev) {
if (i < text.length) {
var c = text.charAt(i);
if (prev == '*' && c == '/') {
code(text, i + 1);
} else {
multilinecomment(text, i + 1, c);
}
}
}
function regex (text, i) {
if (i < text.length) {
var c = text.charAt(i);
if (c == '/') {
code(text, i + 1);
} else {
regex(text, i + 1);
}
}
}
&#13;
<script>
var s = "";
var r = /'allo'/;
// "single line comment"
var f = function(){ return '`a str\'ing`'; };
/** 'multi line'
`comment` **/
var o = { "prop": "va\"'lue" };
var l = '\
a\
multi\
line\
string';
</script>
&#13;