用于匹配/替换 JavaScript 注释的 RegEx(多行和内联)

IT技术 javascript regex comments replace
2021-01-14 19:18:16

我需要使用 JavaScript RegExp 对象从 JavaScript 源中删除所有 JavaScript 注释。

我需要的是 RegExp 的模式。

到目前为止,我发现了这个:

compressed = compressed.replace(/\/\*.+?\*\/|\/\/.*(?=[\n\r])/g, '');

这种模式适用于:

/* I'm a comment */

或用于:

/*
 * I'm a comment aswell
*/

但似乎不适用于内联:

// I'm an inline comment

我不是正则表达式及其模式的专家,所以我需要帮助。

另外,我想要一个 RegEx 模式,它可以删除所有那些类似 HTML 的注释。

<!-- HTML Comment //--> or <!-- HTML Comment -->

还有那些条件 HTML 注释,可以在各种 JavaScript 源中找到。

谢谢。

6个回答

注意:正则表达式不是词法分析器或解析器如果您有一些奇怪的边缘情况,需要从字符串中解析出一些奇怪的嵌套注释,请使用解析器。对于其他 98% 的时间,这个正则表达式应该可以工作。

我有非常复杂的块注释,带有嵌套的星号、斜线等。以下站点的正则表达式就像一个魅力:

http://upshots.org/javascript/javascript-regexp-to-remove-comments
(原件见下文)

进行了一些修改,但保留了原始正则表达式的完整性。为了允许某些双斜杠 ( //) 序列(例如 URL),您必须$1在替换值中使用反向引用而不是空字符串这里是:

/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm

// JavaScript: 
// source_string.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1');

// PHP:
// preg_replace("/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/m", "$1", $source_string);

演示: https : //regex101.com/r/B8WkuX/1

失败的使用案例:有一些边缘情况下,此正则表达式失败。本公开要点中记录了这些案例的持续清单如果您能找到其他案例,请更新要点。

......如果你想删除<!-- html comments -->使用此:

/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*|<!--[\s\S]*?-->$/

(原文 - 仅供历史参考)

// DO NOT USE THIS - SEE ABOVE
/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm
@Ideviantik - 谢谢!我已经更新了我的答案。希望这会继续发展,因为您的解决方案会跳过这样的内容:var foo = "bar";// This is a comment- 所以我在那里添加了一个可选的分号。
2021-03-18 19:18:16
似乎失败了: var foo = "everything /* in this string */ should be kept"
2021-03-18 19:18:16
@DG - 随意获取一个 javascript 解析器并将其用于您的极端情况。上面的正则表达式不是用于解析,而是用于删除文件中的典型注释。如果解析器过度使用,我建议您对斜杠 (/) 或星号 (*) 进行编码或使用连接:"everything /" + "* in this string *" + "/ should be kept"
2021-03-26 19:18:16
@RyanWheale - 冷静。我只是提醒其他人注意。它也失败了foo = "this //is.no.comment"但最大的缺陷是它会剥离“;” ab=a+b; // AB. 原著没有,但它有原作者承认的其他缺陷。顺便说一句,您建议的解决方法仅在我负责将被剥离的代码时才有用。如果是这样,我可以对自己施加各种限制,编写正则表达式将是微不足道的。尽管如此,我还没有找到完美的正则表达式解决方案。这可能(实际上)是不可能的。
2021-04-07 19:18:16
(?:\/\*(?:[\s\S]*?)\*\/)|(?:^\s*\/\/(?:.*)$)应该更好,因为它不会//在字符串中间处理,例如在 urls
2021-04-11 19:18:16

试试这个,

(\/\*[\w\'\s\r\n\*]*\*\/)|(\/\/[\w\s\']*)|(\<![\-\-\s\w\>\/]*\>)

应该管用 :) 在此处输入图片说明

怎么样"foo /* bar */ baz"
2021-03-18 19:18:16
正则表达式没有解决方案。您无法区分 //this 是出现在代码(字符串)内还是出现在行尾(无法计算引号字符(“|”)的数量(获得偶数),因此只能在此之后找到 //comment)
2021-03-19 19:18:16
您的正则表达式将匹配所有 html 标签,而不仅仅是评论。
2021-03-23 19:18:16
这也将匹配 http:// 中的 //,因此 <img src=" foo.com/foo_image.png " /> 将被视为注释!这不是!
2021-04-03 19:18:16
不要使用这个正则表达式!它还匹配http://和任何其他具有//或 的正则表达式/*所以无法使用
2021-04-03 19:18:16

我一直在把一个需要做类似事情的表达式放在一起。
成品是:

/(?:((["'])(?:(?:\\\\)|\\\2|(?!\\\2)\\|(?!\2).|[\n\r])*\2)|(\/\*(?:(?!\*\/).|[\n\r])*\*\/)|(\/\/[^\n\r]*(?:[\n\r]+|$))|((?:=|:)\s*(?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/))|((?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/)[gimy]?\.(?:exec|test|match|search|replace|split)\()|(\.(?:exec|test|match|search|replace|split)\((?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/))|(<!--(?:(?!-->).)*-->))/g

很吓人吧?

分解一下,第一部分匹配单引号或双引号内的任何内容
这是避免匹配带引号的字符串所必需的

((["'])(?:(?:\\\\)|\\\2|(?!\\\2)\\|(?!\2).|[\n\r])*\2)

第二部分匹配由 /* */ 分隔的多行注释

(\/\*(?:(?!\*\/).|[\n\r])*\*\/)

第三部分匹配从行中任意位置开始的单行注释

(\/\/[^\n\r]*(?:[\n\r]+|$))

第四到第六部分匹配正则表达式中的任何内容
这依赖于前面的等号或正则表达式调用之前或之后的文字

((?:=|:)\s*(?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/))
((?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/)[gimy]?\.(?:exec|test|match|search|replace|split)\()
(\.(?:exec|test|match|search|replace|split)\((?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/))

我最初忘记的第七个删除了html评论

(<!--(?:(?!-->).)*-->)

我的开发环境遇到了一个问题,它为一个断线的正则表达式发出错误,所以我使用了以下解决方案

var ADW_GLOBALS = new Object
ADW_GLOBALS = {
  quotations : /((["'])(?:(?:\\\\)|\\\2|(?!\\\2)\\|(?!\2).|[\n\r])*\2)/,
  multiline_comment : /(\/\*(?:(?!\*\/).|[\n\r])*\*\/)/,
  single_line_comment : /(\/\/[^\n\r]*[\n\r]+)/,
  regex_literal : /(?:\/(?:(?:(?!\\*\/).)|\\\\|\\\/|[^\\]\[(?:\\\\|\\\]|[^]])+\])+\/)/,
  html_comments : /(<!--(?:(?!-->).)*-->)/,
  regex_of_doom : ''
}
ADW_GLOBALS.regex_of_doom = new RegExp(
  '(?:' + ADW_GLOBALS.quotations.source + '|' + 
  ADW_GLOBALS.multiline_comment.source + '|' + 
  ADW_GLOBALS.single_line_comment.source + '|' + 
  '((?:=|:)\\s*' + ADW_GLOBALS.regex_literal.source + ')|(' + 
  ADW_GLOBALS.regex_literal.source + '[gimy]?\\.(?:exec|test|match|search|replace|split)\\(' + ')|(' + 
  '\\.(?:exec|test|match|search|replace|split)\\(' + ADW_GLOBALS.regex_literal.source + ')|' +
  ADW_GLOBALS.html_comments.source + ')' , 'g'
);

changed_text = code_to_test.replace(ADW_GLOBALS.regex_of_doom, function(match, $1, $2, $3, $4, $5, $6, $7, $8, offset, original){
  if (typeof $1 != 'undefined') return $1;
  if (typeof $5 != 'undefined') return $5;
  if (typeof $6 != 'undefined') return $6;
  if (typeof $7 != 'undefined') return $7;
  return '';
}

这将返回由引用的字符串文本捕获的任何内容以及在正则表达式中找到的任何内容完整无缺,但为所有注释捕获返回一个空字符串。

我知道这太过分了,而且很难维护,但到目前为止它似乎对我有用。

我进入SyntaxError: unterminated parenthetical了 Firefox。
2021-03-14 19:18:16
我做了一些更改并抛出了一个 js 小提琴,以便更容易复制。链接希望这有帮助。请注意 - 这适用于脚本和大多数其他代码,但如果您获得任何带括号的自由文本,您将遇到麻烦。代码不知道如何处理 ' in 本身不在引号中时
2021-03-15 19:18:16
我想出了这个专门处理javascript代码。不幸的是,它不适用于一般文本,但那是因为它是一个完全不同的用例。无论如何,您能否将更广泛的测试用例放在小提琴中并删除链接?知道这将解决哪些问题对我来说非常有帮助。即使没有其他人使用它,我也需要知道它在哪里因我自己的使用而中断。
2021-03-23 19:18:16
它不起作用。Transforms: function(field) { // 注释示例 return new field('like').equal('no'); } into "function (field) {return new field().equal();}" 引号之间的任何内容都被删除。
2021-03-23 19:18:16
“不知道如何处理 [单引号,如果它没有出现] 在引号中” - 这是一个非常重要的事实要注意。坦率地说,它使该表达式无法用于大多数通用需求。使用单引号代替双引号是很常见的。但是我的测试显示表达式存在更严重的问题。您小提琴中的测试用例非常有限。我有一个更广泛的测试用例,并且该表达式在许多地方严重破坏了它。恕我直言,尝试修复是没有意义的。我的研究强烈表明,没有一个正则表达式可以充分完成这项工作。
2021-03-26 19:18:16

这适用于几乎所有情况:

var RE_BLOCKS = new RegExp([
  /\/(\*)[^*]*\*+(?:[^*\/][^*]*\*+)*\//.source,           // $1: multi-line comment
  /\/(\/)[^\n]*$/.source,                                 // $2 single-line comment
  /"(?:[^"\\]*|\\[\S\s])*"|'(?:[^'\\]*|\\[\S\s])*'/.source, // - string, don't care about embedded eols
  /(?:[$\w\)\]]|\+\+|--)\s*\/(?![*\/])/.source,           // - division operator
  /\/(?=[^*\/])[^[/\\]*(?:(?:\[(?:\\.|[^\]\\]*)*\]|\\.)[^[/\\]*)*?\/[gim]*/.source
  ].join('|'),                                            // - regex
  'gm'  // note: global+multiline with replace() need test
);

// remove comments, keep other blocks
function stripComments(str) {
  return str.replace(RE_BLOCKS, function (match, mlc, slc) {
    return mlc ? ' ' :         // multiline comment (replace with space)
           slc ? '' :          // single/multiline comment
           match;              // divisor, regex, or string, return as-is
  });
}

代码基于 jspreproc 中的正则表达式,我为riot compiler编写了这个工具

http://github.com/aMarCruz/jspreproc

在简单的 JS 正则表达式中,这个:

my_string_or_obj.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, ' ')
这有效!虽然也许用 '` '`(一个空格)代替 ''
2021-03-13 19:18:16
谢谢!我看过 10 种不同的 RegEx,这是唯一一种在每种情况下都能完美运行的!
2021-03-15 19:18:16
使用给定的正则表达式,以下答案给出了3//. p = /\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm;` x='3//'; x.match(p);
2021-03-27 19:18:16