RegEx для соответствия / замены комментариев JavaScript (как многострочных, так и встроенных) - PullRequest
37 голосов
/ 13 мая 2011

Мне нужно удалить все комментарии JavaScript из источника JavaScript с помощью объекта JavaScript RegExp.

Мне нужен шаблон для RegExp.

Пока я нашел это:

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

Этот шаблон работает нормально для:

/* I'm a comment */

или для:

/*
 * I'm a comment aswell
*/

Но, похоже, не работает для встроенного:

// I'm an inline comment

Я не совсем эксперт по RegEx и его шаблонам, поэтому мне нужна помощь.

Кроме того, я хотел бы иметь шаблон RegEx, который удалял бы все эти HTML-подобныекомментарии.

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

А также те условные комментарии HTML, которые можно найти в различных источниках JavaScript.

Спасибо.

Ответы [ 12 ]

66 голосов
/ 28 февраля 2013

ПРИМЕЧАНИЕ: Regex не является лексером или парсером .Если у вас есть какой-то странный крайний случай, когда вам нужно разобрать некоторые странно вложенные комментарии из строки, используйте парсер.В остальное 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);

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

НЕИСПРАВНОСТЬ ИСПОЛЬЗОВАНИЯ: Есть несколько крайних случаев, когда это регулярное выражение не выполняется,Постоянный список этих случаев задокументирован в этом публичном документе .Пожалуйста, обновите суть, если вы можете найти другие случаи.

... и если вы также хотите удалить <!-- html comments --> используйте это:

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

(оригинал- только для ознакомления)

// DO NOT USE THIS - SEE ABOVE
/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm
18 голосов
/ 13 мая 2011

попробуйте это,

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

должно работать :) enter image description here

6 голосов
/ 14 октября 2013

Я поместил вместе с выражением, которое должно сделать что-то похожее.
готовый продукт:

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

Возвращает все, что захвачено в тексте строки в кавычках, и все, что найдено в литерале регулярного выражения, но возвращает пустую строку для всех захваченных комментариев.

Я знаю, что это чрезмерно и довольно сложно поддерживать, но пока мне кажется, что это работает.

2 голосов
/ 24 сентября 2015

Это работает почти во всех случаях:

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

1 голос
/ 28 ноября 2018

немного проще -

это работает также для многострочных - (<!--.*?-->)|(<!--[\w\W\n\s]+?-->)

enter image description here

1 голос
/ 15 ноября 2017

В простом простом регулярном выражении JS это:

my_string_or_obj.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, ' ')
1 голос
/ 16 января 2016

Если вы нажмете на ссылку ниже, вы найдете скрипт удаления комментариев, написанный в регулярном выражении.

Это 112 строк кода, которые работают вместе, также работают с mootools и Joomla, drupal и другими сайтами cms. Протестировано на 800.000 строк кода и комментариев. работает отлично. Этот также выбирает несколько скобок (abc (/ nn / ('/ xvx /')) "// строка тестирования") и комментарии, которые находятся между двоеточиями, и защищают их. 23-01-2016 ..! Это код с комментариями. !!!!

Нажмите здесь

1 голос
/ 10 июля 2015

Это поздно, чтобы быть очень полезным для первоначального вопроса, но, возможно, это кому-то поможет.

Основываясь на ответе @Ryan Wheale, я обнаружил, что это работает как всеобъемлющий захват, чтобы гарантировать, что совпадения исключают все, что находится внутри строкового литерала.

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

Последняя группа (все остальные отбрасываются) основана на ответе Райана. Пример здесь .

Предполагается, что код хорошо структурирован и является допустимым JavaScript.

Примечание: это не было проверено на плохо структурированном коде, который может или не может быть восстановлен в зависимости от собственной эвристики движка javascript.

Примечание: это должно выполняться для действительного javascript многострочные строковые литералы , и в этом случае это регулярное выражение почти наверняка сломается, хотя этот случай не был проверен.


Однако в литерале регулярных выражений можно сопоставить что-то, похожее на комментарий (см. Комментарии / результаты в приведенном выше примере).

Я использую описанный выше захват после замены всех литералов регулярных выражений, используя следующий всеобъемлющий захват, извлеченный из es5-lexer здесь и здесь , как указано в Mike Samuel ответ на этот вопрос :

/(?:(?: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

Для полноты см. Также это тривиальное предостережение .

0 голосов
/ 03 октября 2018

Я тоже искал быстрое решение 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;
}
0 голосов
/ 16 мая 2018

Для комментария к блоку: 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

...