在JavaScript中查找文本string
我有一个有效的JavaScript文件(utf-8),我需要从中自动提取所有文本string。
为了简单起见,该文件中不包含任何注释块,只有有效的ES6 JavaScript代码。
一旦我find'
或"
或“的事件,我应该扫描文本块的末尾,是所有可能的变化,如"'"
, '"'
,' “,”\“, '"
,”\“等。
有没有一个已知和/或可重复使用的algorithm来检测有效的ES6 JavaScript文本块的结束?
更新-1:我的JavaScript文件不只是大,我也必须作为一个stream块,处理它,所以正则expression式绝对不可用。 我不想让我的问题复杂化,提到联合的代码块,我会自己弄清楚,如果我有一个algorithm,可以为内存中的单一代码工作。
更新-2:我得到了这个工作最初,感谢这里给出的许多build议,但由于正则expression式再次卡住了。
正则expression式的例子,打破迄今为止build议的任何文本检测技术:
/'/ /"/ /\`/
通过仔细研究这个问题,通过阅读: JavaScript如何检测正则expression式? ,恐怕在JavaScript中检测正则expression式是一个全新的球类游戏,值得单独的一个问题,否则就太复杂了。 但是,如果有人能够在这个问题上指出我的正确方向,我非常感激。
更新3:经过大量的研究后,我很遗憾地发现,我不能提出一个适用于我的情况的algorithm,因为正则expression式的存在使得任务比最初想象的要复杂得多。 根据以下内容: 当parsingJavaScript时,什么决定了斜杠的含义? ,确定JavaScript中正则expression式的开始和结束是最复杂和最复杂的任务之一。 没有它,我们不知道什么时候符号'
,'''和'打开一个文本块,或者它们是否在正则expression式中。
parsingJavaScript的唯一方法是使用JavaScriptparsing器。 即使你能够使用正则expression式,在一天结束的时候,他们还没有足够强大的力量去做你正在做的事情。
你可以使用几个现有的parsing器之一,这是非常容易使用,或者你可以写你自己的,简化,专注于string提取问题。 我很难想象你想写自己的parsing器,即使是简单的parsing器。 你会花更多的时间来写和维护它比你想象的要多。
例如,一个现有的parsing器将会处理类似于下面的内容,而不会冒汗。
`foo${"bar"+`baz`}`
parsing器使用的明显候选者是esprima和babel。
顺便说一下,一旦你提取这些string,你打算怎么做?
如果你只需要一个近似的答案,或者如果你想得到的string完全按照它们在源代码中出现的那样,那么正则expression式就可以完成这个工作。
鉴于string文字"\n"
,你期望一个单字符的string包含一个换行符或两个字符反斜杠和n?
- 在前一种情况下,您需要像JavaScript解释器一样解释转义序列。 你需要的是JavaScript的词法分析器 ,许多人已经编写了这段代码。
- 在后一种情况下,正则expression式必须识别
\x40
和\u2026
等转义序列,所以即使在这种情况下,您也应该从现有的JavaScript词法分析器复制代码。
请参阅https://github.com/douglascrockford/JSLint/blob/master/jslint.js ,函数tokenize
。
尝试下面的代码:
txt = "var z,b \n;z=10;\nb='321`1123`321321';\nc='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));
我可以让你自己testing一下吗? 我相信,你应该能够使用这个解决scheme,经过一些调整(例如,重新设置为0为每个新的块可能是一个很好的起点)。 我可以继续处理你的问题,但是我希望你告诉我是否正朝着正确的方向前进:-)
此代码使用recursion来跟踪当前状态(代码,string,注释或正则expression式)。 我不熟悉处理大文件,因此恐怕会导致堆栈溢出。 作为一种解决方法,您可以将状态保存在全局variables中,并以迭代的方式完成所有这些工作。
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); } } }
<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>