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

时间:2011-05-13 08:36:30

标签: javascript regex comments replace

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

我需要的是RegExp的模式。

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

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

此模式适用于:

/* I'm a comment */

或for:

/*
 * I'm a comment aswell
*/

但似乎不适用于内联:

// I'm an inline comment

我不是RegEx的专家和它的模式,所以我需要帮助。

此外,我希望有一个RegEx模式,可以删除所有类似HTML的注释。

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

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

感谢。

15 个答案:

答案 0 :(得分:64)

注意:Regex is not a lexer or a parser。如果您有一些奇怪的边缘情况,您需要从字符串中解析出一些奇怪的嵌套注释,请使用解析器。对于其他98%的时间,这个正则表达式应该有效。

我使用嵌套的星号,斜杠等进行了非常复杂的块注释。以下网站的正则表达式就像一个魅力:

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

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

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

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

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

DEMO: http://www.regextester.com/?fam=96247

未通过使用案例:此正则表达式失败的边缘情况有一些。 this public gist中记录了这些案例的持续列表。如果您能找到其他案例,请更新要点。

...如果您想要删除<!-- html comments -->,请使用此代码:

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

(原件 - 仅供参考)

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

答案 1 :(得分:17)

试试这个,

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

应该工作:) enter image description here

答案 2 :(得分:6)

我一直在做一个需要做类似事情的表达 成品是:

/(?:((["'])(?:(?:\\\\)|\\\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 '';
}

这会返回由引用的字符串文本捕获的任何内容以及在正则表达式文字中找不到的任何内容,但会返回所有注释捕获的空字符串。

我知道这是过度而且难以维护,但到目前为止它似乎对我有用。

答案 3 :(得分:2)

这对于原始问题来说已经很晚了,但也许它会对某人产生帮助。

基于@Ryan Wheale的回答,我发现这可以作为一个全面的捕获工作,以确保匹配排除字符串文字中的任何内容。

/(?:\r\n|\n|^)(?:[^'"])*?(?:'(?:[^\r\n\\']|\\'|[\\]{2})*'|"(?:[^\r\n\\"]|\\"|[\\]{2})*")*?(?:[^'"])*?(\/\*(?:[\s\S]*?)\*\/|\/\/.*)/g

最后一组(所有其他组都被丢弃)是基于Ryan的答案。示例here

这假设代码结构良好且有效的javascript。

注意:尚未对结构不良的代码进行测试,根据javascript引擎自身的启发式方法,这些代码可能会或可能无法恢复。

注意:这应该适用于有效的javascript&lt;但是,ES6允许multi-line string literals,在这种情况下,这个正则表达式几乎肯定会破坏,尽管这种情况还没有经过测试。

但是,仍然可以在正则表达式文字中匹配看起来像注释的内容(请参阅上面示例中的注释/结果)。

我使用从es5-lexer herehere中提取的以下全面捕获替换所有正则表达式文字后使用上面的捕获,如Mike Samuel的答案中所述this question

/(?:(?:break|case|continue|delete|do|else|finally|in|instanceof|return|throw|try|typeof|void|[+]|-|[.]|[/]|,|[*])|[!%&(:;<=>?[^{|}~])?(\/(?![*/])(?:[^\\\[/\r\n\u2028\u2029]|\[(?:[^\]\\\r\n\u2028\u2029]|\\(?:[^\r\n\u2028\u2029ux]|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}))+\]|\\(?:[^\r\n\u2028\u2029ux]|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}))*\/[gim]*)/g

为完整起见,另请参阅this trivial caveat

答案 4 :(得分:2)

几乎适用于所有情况:

"Destination ": "Fuerteventura"{
    "Hotel_name": "Aloe Club",
    "USP": "Børnevenligt;;Lejligheder op til 6 personer;;Tre dejlige poolområder ",
    "Fra-pris": "1234",
    "Se_flere_rejser_URL": "http:\/\/www.spies.dk\/vinterferie",
    "Læs_mere_her_URL ": "http:\/\/www.spies.dk\/de-kanariske-oer\/corralejo\/hoteller",
    "Image_url": "https:\/\/spies-isobar.s3.amazonaws.com\/1355_Spies_AVO\/cp\/destination\/a\/a\/image1.jpg",
    "id": 0,


    "Hotel_name": "SunConnect Atlantis Fuerteventura Resort",
    "USP": "Børnevenligt;;All Inclusive indgår;;Mange aktiviteter for hele familien ",
    "Fra-pris": "123",
    "Se_flere_rejser_URL": "http:\/\/www.spies.dk\/vinterferie",
    "Læs_mere_her_URL ": "http:\/\/www.spies.dk\/de-kanariske-oer\/corralejo\/hoteller",
    "Image_url": "https:\/\/spies-isobar.s3.amazonaws.com\/1355_Spies_AVO\/cp\/destination\/a\/a\/image1.jpg",
    "id": 1
},

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

请参阅http://github.com/aMarCruz/jspreproc

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

仅用于多行的简单正则表达式:

/\*((.|\n)(?!/))+\*/

答案 7 :(得分:1)

如果单击下面的链接,则会找到用regex编写的注释删除脚本。

这些是关闭代码的112行,它们可以与mootools和Joomla以及drupal和其他cms网站一起使用。 测试了800.000行代码和注释。工作良好。 这个也选择多个括号(abc(/ nn /('/ xvx /'))“//测试行”)和冒号之间的注释和保护他们。 23-01-2016 ..!这是带有注释的代码。!!!!

Click Here

答案 8 :(得分:1)

更简单-

这也适用于多行-(<!--.*?-->)|(<!--[\w\W\n\s]+?-->)

enter image description here

答案 9 :(得分:0)

我想知道这是否是一个技巧问题 一位教授给学生。为什么?因为看来 对我来说,做到这一点是不可能 正则表达式,一般情况下。

您(或其代码)可以包含 像这样有效的JavaScript:

let a = "hello /* ";
let b = 123;
let c = "world */ ";

现在,如果你有一个删除所有内容的正则表达式 在一对/ *和* /之间,它会破坏代码 上面,它将删除中的可执行代码 中间也是。

如果你试图设计一个不能的正则表达式 删除包含引号的注释 你不能删除这样的评论。这适用 单引号,双引号和后引号。

您无法使用常规删除(所有)评论 JavaScript中的表达式,在我看来, 也许有人可以指出一种方法 它适用于上述情况。

你可以做的是构建一个小的解析器 逐个字符地遍历代码 并知道它何时在字符串内以及何时 它在评论里面,当它在里面时 字符串内的注释等等。

我确信有很好的开源JavaScript 可以做到这一点的解析器。也许有些人 包装和缩小工具可以做到这一点 你也是。

答案 10 :(得分:0)

块评论: https://regex101.com/r/aepSSj/1

仅当斜杠字符后跟星号时才匹配斜杠字符(\1)。

(\/)(?=\*)

可能后跟另一个星号

(?:\*)

接下来是第一组匹配,或者来自某个东西的零次或多次......也许,不记得匹配但是作为一组捕获。

((?:\1|[\s\S])*?)

后跟星号和第一组

(?:\*)\1

对于块和/或内联注释: https://regex101.com/r/aepSSj/2

其中|表示或(?=\/\/(.*))捕获任何//之后的任何内容

https://regex101.com/r/aepSSj/3 也抓住了第三部分

全部在:https://regex101.com/r/aepSSj/8

答案 11 :(得分:0)

我也在寻找一种快速的Regex解决方案,但是没有一个答案能100%起作用。每个人最终都以某种方式破坏了源代码,这主要是由于在字符串文字中检测到注释。例如

var string = "https://www.google.com/";

成为

var string = "https:

为了使那些来自Google的人受益,我最终编写了一个简短的函数(使用Javascript),该函数实现了Regex无法完成的工作。修改您用来解析Javascript的任何语言。

function removeCodeComments(code) {
    var inQuoteChar = null;
    var inBlockComment = false;
    var inLineComment = false;
    var inRegexLiteral = false;
    var newCode = '';
    for (var i=0; i<code.length; i++) {
        if (!inQuoteChar && !inBlockComment && !inLineComment && !inRegexLiteral) {
            if (code[i] === '"' || code[i] === "'" || code[i] === '`') {
                inQuoteChar = code[i];
            }
            else if (code[i] === '/' && code[i+1] === '*') {
                inBlockComment = true;
            }
            else if (code[i] === '/' && code[i+1] === '/') {
                inLineComment = true;
            }
            else if (code[i] === '/' && code[i+1] !== '/') {
                inRegexLiteral = true;
            }
        }
        else {
            if (inQuoteChar && ((code[i] === inQuoteChar && code[i-1] != '\\') || (code[i] === '\n' && inQuoteChar !== '`'))) {
                inQuoteChar = null;
            }
            if (inRegexLiteral && ((code[i] === '/' && code[i-1] !== '\\') || code[i] === '\n')) {
                inRegexLiteral = false;
            }
            if (inBlockComment && code[i-1] === '/' && code[i-2] === '*') {
                inBlockComment = false;
            }
            if (inLineComment && code[i] === '\n') {
                inLineComment = false;
            }
        }
        if (!inBlockComment && !inLineComment) {
            newCode += code[i];
        }
    }
    return newCode;
}

答案 12 :(得分:0)

2019:

所有答案都与合适的答案有关,所以我写了一些行之有效的方法,尝试一下:

function scriptComment(code){
        const savedText = [];
        return code
           .replace(/(['"`]).*?\1/gm,function (match) {
            var i = savedText.push(match);
            return (i-1)+'###';
        })
        // remove  // comments
        .replace(/\/\/.*/gm,'')
        // now extract all regex and save them
        .replace(/\/[^*\n].*\//gm,function (match) {
            var i = savedText.push(match);
            return (i-1)+'###';
        })
        // remove /* */ comments
        .replace(/\/\*[\s\S]*\*\//gm,'')
        // remove <!-- --> comments
        .replace(/<!--[\s\S]*-->/gm, '')
        .replace(/\d+###/gm,function(match){
            var i = Number.parseInt(match);
            return  savedText[i];
        })
       
    }
    var cleancode = scriptComment(scriptComment.toString())
    console.log(cleancode)


旧答案:不能处理这样的示例代码:

// won't execute the creative code ("Can't execute code form a freed script"),
navigator.userAgent.match(/\b(MSIE |Trident.*?rv:|Edge\/)(\d+)/);

function scriptComment(code){
    const savedText = [];
    return code
          // extract strings and regex 
        .replace(/(['"`]).*?\1/gm,function (match) {
            savedText.push(match);
            return '###';
        })
        // remove  // comments
        .replace(/\/\/.*/gm,'')
        // now extract all regex and save them
        .replace(/\/[^*\n].*\//gm,function (match) {
            savedText.push(match);
            return '###';
        })
        // remove /* */ comments
        .replace(/\/\*[\s\S]*\*\//gm,'')
        // remove <!-- --> comments
        .replace(/<!--[\s\S]*-->/gm, '')
        /*replace \ with \\ so we not lost \b && \t*/
        .replace(/###/gm,function(){
            return savedText.shift();
        })
   
}
var cleancode = scriptComment(scriptComment.toString())
console.log(cleancode)

答案 13 :(得分:0)

已接受的解决方案并未涵盖所有常见用例。请参阅此处的示例:https://regex101.com/r/38dIQk/1

以下正则表达式应该更可靠地匹配 JavaScript 注释:

val customProgressAnimationSpec = SpringSpec(
    dampingRatio = 1f,
    stiffness = 50f,
    visibilityThreshold = 1 / 1000f
)

要进行演示,请访问以下链接:https://regex101.com/r/z99Nq5/1/

答案 14 :(得分:-1)

根据上述尝试并使用UltraEdit(主要是Abhishek Simon),我发现这适用于内联注释并处理注释中的所有字符。

(\s\/\/|$\/\/)[\w\s\W\S.]*

这匹配行开头的注释或//

之前的空格
  

// public static final String LETTERS_WORK_FOLDER =   “/信函/生成/工作”;

但不是

  

“http://schemas.us.com.au/hub/'>” +

所以它只对

这样的东西不好
  

if(x){f(x)} //其中f是某个函数

它只需要

  

if(x){f(x)} //其中f是函数