在JavaScript中查找文本字符串

8
我有一个大型的有效JavaScript文件(utf-8),需要自动提取其中的所有文本字符串。
为简单起见,该文件不包含任何注释块,只有有效的ES6 JavaScript代码。
一旦我找到'"或`的出现,我应该扫描文本块的结尾,这就是我卡住的地方,因为有很多可能的变化,比如"'"'"'、"\'"、'\"'、'"、`\``等等。
是否有已知和/或可重用的算法来检测有效的ES6 JavaScript文本块的结尾?
更新1:我的JavaScript文件不仅很大,而且我还必须将其作为流在块中处理,因此Regex绝对不能使用。我不想让问题复杂化,提到代码块的联合,如果我有一个可以针对内存中单个代码片段工作的算法,我会自己解决。
更新2:我最初通过许多建议使其工作,但由于正则表达式,我又卡住了。
正则表达式的示例会破坏到目前为止建议的任何文本检测技术:
/'/
/"/
/\`/

经过仔细研究,阅读此文:How does JavaScript detect regular expressions?,我恐怕在JavaScript中检测正则表达式是一个全新的难题,值得分开讨论,否则会变得太复杂。但如果有人能为我指点迷津,我将不胜感激... 更新3: 经过多方调查研究,我很遗憾地发现在我的情况下我无法提供可行的算法,因为正则表达式的存在使任务变得比最初想象的要复杂得多。根据以下链接所述:When parsing Javascript, what determines the meaning of a slash?,确定JavaScript中正则表达式的开头和结尾是最复杂和费解的任务之一。而没有这些信息,我们就不能确定符号'、'"'和`是否正在打开文本块或者它们是否在正则表达式内部。

你能提供一些例子吗? - saruftw
@saru95 什么样的例子?JavaScript 文本字符串的例子吗? - vitaly-t
1
也许类似于 esprima - Xotic750
1
我仍然会选择像Esprima这样的工具,并搜索引用值的原始值。我认为重复造轮子没有意义。(它甚至可能有一些聪明的选项,让你直接做想要的事情) - Xotic750
3
要解析JS,请使用JS解析器。 完毕。 - user663031
显示剩余13条评论
3个回答

4
唯一解析 JavaScript 的方法是使用 JavaScript 解析器。即使您能够使用正则表达式,到最后它们也没有足够的能力来做您在此尝试做的事情。
您可以使用几个现有的解析器之一,这些解析器非常易于使用;或者您可以编写自己的解析器,简化重点放在字符串提取问题上。我几乎不想想象您想要编写自己的解析器,即使是简化版的。相比您想的可能花费更多的时间编写和维护它。
例如,现有的解析器将毫不费力地处理以下内容。
`foo${"bar"+`baz`}`

明显的解析器选择是esprima和babel。
顺便问一下,您打算在提取这些字符串后用它们做什么?

如果您的建议更具体一些,例如从这里开始:https://astexplorer.net/,那么它会更有用。请理解对于任何新手来说,AST解析器可能很难理解,并且需要弄清楚要使用哪个以及为什么要使用它。 - vitaly-t
我几乎看不出来我怎么可能比建议esprima和babel更具体了。Esprima有一个易于找到的在线沙箱。 - user663031
当我提出这个问题时,我甚至从未听说过AST解析器,更不用说理解它们如何帮助我了。但是在对这个主题进行了非常广泛的研究之后,我现在明白了。这就是我所说的,你的答案对于没有任何AST解析器经验的人来说不够具体的意思。 - vitaly-t
我认为语句 The obvious candidates for parsers to use are esprima and babel. 有争议。如果你查看https://astexplorer.net/,你会发现选择并不显然,它们都有优缺点。 - vitaly-t
@vitaly-t 很抱歉我没有关注那些不熟悉解析器问题的人,并且我的回答“只需使用解析器”所暗示的漫不经心的态度。为此我辩解说,在StackOverflow问答格式中,我怀疑JS解析器的概念是否适合于介绍,但另一方面我也可以提供一个简单的例子。 - user663031
我接受这个答案,更多的是因为在我的情况下,即使问题不再相关,我已经超越了它,并且在esprima的帮助下完成了我想要的一切。另一个问题 - https://dev59.com/BpLea4cB1Zd3GeqP3YeT 更有趣,也是关于这个主题的一个非常实用的例子。 - vitaly-t

0

如果你只需要一个近似的答案,或者想要得到与源代码中完全相同的字符串文字,那么正则表达式可以胜任这项工作。

给定字符串文字"\n",你期望得到包含换行符的单字符字符串还是包含反斜杠和n两个字符的字符串?

  • 在前一种情况下,你需要像JavaScript解释器一样精确地解释转义序列。你需要一个JavaScript的词法分析器,许多人已经编写了这段代码。
  • 在后一种情况下,正则表达式必须识别像\x40\u2026这样的转义序列,因此即使在这种情况下,你也应该从现有的JavaScript词法分析器中复制代码。

请参见https://github.com/douglascrockford/JSLint/blob/master/jslint.js,函数tokenize


简单来说,一旦我找到文本开头符号的索引,比如 '" 或 `, 我需要找到相应文本结束符号的索引。而且我不确定正则表达式是否适用于大型 JavaScript 文件。 - vitaly-t
那个名为 tokenize 的方法似乎占据了整个库的大部分,它非常庞大。如果可能的话,我希望有更简单的方法。 - vitaly-t

-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));

如果您在输入字符串末尾删除了;,算法将不再起作用... - vitaly-t
@vitaly-t 谢谢,代码已更新,只需将 txt.slice(i+1,-1) 替换为 txt.slice(i+1)。希望对您有用。 - Andriy Ivaneyko
你定义了 fetchStrings 函数来接收一个 breaker 参数,但是从未使用过它。另外,这个函数能够处理像 "foo\"bar" 这样的字符串吗? - user663031
请查看我在问题中的更新-2。 - vitaly-t

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接