web-dev-qa-db-fra.com

RegEx pour correspondre/remplacer les commentaires JavaScript (multiligne et en ligne)

Je dois supprimer tous les commentaires JavaScript d'une source JavaScript à l'aide de l'objet JavaScript RegExp.

Ce dont j'ai besoin, c'est le modèle pour RegExp.

Jusqu'à présent, j'ai trouvé ceci:

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

Ce modèle fonctionne bien pour:

/* I'm a comment */

ou pour:

/*
 * I'm a comment aswell
*/

Mais ne semble pas fonctionner pour le inline:

// I'm an inline comment

Je ne suis pas un expert pour RegEx et ses modèles, j'ai donc besoin d'aide.

En outre, je voudrais avoir un modèle RegEx qui supprimerait tous ces commentaires de type HTML.

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

Et aussi ces commentaires HTML conditionnels, qui peuvent être trouvés dans diverses sources JavaScript.

Merci.

33
metaforce

essaye ça,

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

devrait marcher :)enter image description here

17
abi1964

NOTE: Regex n'est pas un lexer ou un analyseur . Si vous avez des cas étranges dans lesquels vous avez besoin d'analyser des commentaires étrangement imbriqués dans une chaîne, utilisez un analyseur. Pour les autres 98% du temps, cette expression régulière devrait fonctionner.

J'avais des commentaires de bloc assez complexes avec des astérisques imbriqués, des barres obliques, etc. L'expression régulière sur le site suivant fonctionnait à merveille:

http://upshots.org/javascript/javascript-regexp-to-remove-comments
(voir ci-dessous pour l'original)

Quelques modifications ont été apportées, mais l'intégrité de la regex originale a été préservée. Afin de permettre certaines séquences en double barre oblique (//) (telles que les URL), vous devez utiliser la référence arrière $1 dans votre valeur de remplacement au lieu d'une chaîne vide. C'est ici:

/\/\*[\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

FAILING USE CASES: Il y a quelques cas Edge où cette expression rationnelle échoue. Une liste continue de ces cas est documentée dans cet article de synthèse public . S'il vous plaît mettre à jour le Gist si vous pouvez trouver d'autres cas.

... et si vous aussi voulez supprimer <!-- html comments -->, utilisez ceci:

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

(original - pour référence historique seulement)

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

J'ai rassemblé une expression qui doit faire quelque chose de similaire.
le produit fini est: 

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

Effrayant non?

Pour le décomposer, la première partie correspond à quoi que ce soit entre guillemets simples ou doubles
Ceci est nécessaire pour éviter la correspondance des chaînes citées

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

la deuxième partie correspond aux commentaires multilignes délimités par/* * /

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

La troisième partie correspond aux commentaires d'une seule ligne commençant n'importe où dans la ligne.

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

Les quatrième à sixième parties correspondent à quoi que ce soit dans un littéral regex
Cela repose sur un signe égal précédent ou sur le caractère littéral avant ou après un appel regex

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

et le septième que j'ai oublié à l'origine supprime les commentaires html

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

J'ai eu un problème avec mon environnement de développement en émettant des erreurs pour une regex qui a cassé une ligne, alors j'ai utilisé la solution suivante

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 '';
}

Cela renvoie tout ce qui est capturé par le texte de chaîne cité et tout ce qui est trouvé dans un littéral de regex intact, mais renvoie une chaîne vide pour toutes les captures de commentaires.

Je sais que c’est excessif et assez difficile à maintenir, mais cela semble fonctionner jusqu’à présent pour moi.

6
wolffer-east

En langage simple, JS regex, ceci:

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

C’est tard pour être très utile à la question initiale, mais cela aidera peut-être quelqu'un.

D'après la réponse de @Ryan Wheale, j'ai constaté que cela fonctionnait comme une capture complète afin de garantir que les correspondances excluent tout élément trouvé dans un littéral de chaîne.

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

Le dernier groupe (tous les autres sont éliminés) est basé sur la réponse de Ryan. Exemple ici .

Cela suppose que le code est correctement structuré et que javascript est valide.

Remarque: ceci n'a pas été testé sur du code mal structuré pouvant ou non être récupérable en fonction de l'heuristique propre au moteur javascript.

Remarque: ceci devrait être valable pour le javascript valide <ES6. Cependant, ES6 autorise littéraux de chaînes multilignes , auquel cas cette expression régulière sera probablement cassée, bien que ce cas n'ait pas été testé.


Cependant, il est toujours possible de faire correspondre quelque chose qui ressemble à un commentaire dans un littéral regex (voir commentaires/résultats dans l'exemple ci-dessus).

J'utilise la capture ci-dessus après avoir remplacé tous les littéraux de regex en utilisant la capture complète suivante extraite de es5-lexer ici et ici , comme indiqué dans la réponse de Mike Samuel à cette 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

Pour plus de détails, voir aussi cet avertissement trivial .

2
Nolo

Cela fonctionne pour presque tous les cas:

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

Le code est basé sur les expressions rationnelles de jspreproc, j’ai écrit cet outil pour le compilateur riot .

Voir http://github.com/aMarCruz/jspreproc

2
aMarCruz

un peu plus simple - 

cela fonctionne aussi pour multiline - (<!--.*?-->)|(<!--[\w\W\n\s]+?-->)

 enter image description here

1
Aurielle Perlmann

Si vous cliquez sur le lien ci-dessous, vous trouvez un script de suppression de commentaire écrit en regex. 

Ce sont 112 lignes de code qui fonctionnent ensemble qui fonctionnent également avec mootools et les sites Web Joomla et drupal et autres cms. Testé sur 800.000 lignes de code et commentaires. fonctionne bien. Celui-ci sélectionne également plusieurs parenthèses comme (abc (/ nn/('/ xvx /')) "// ligne de test") et les commentaires placés entre deux points et les protégeant __. 23-01-2016 ..! C'est le code avec les commentaires qu'il contient. !!!! 

Cliquez ici

1
John Smith

Je cherchais aussi une solution rapide de Regex, mais aucune des réponses fournies ne fonctionnait à 100%. Chacune d'elles finit par casser le code source d'une manière ou d'une autre, principalement à cause de commentaires détectés dans des littéraux de chaîne. Par exemple.

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

Devient

var string = "https:

Pour le bénéfice de ceux qui viennent de Google, j'ai fini par écrire une courte fonction (en Javascript) qui permet de réaliser ce que Regex ne pouvait pas faire. Modifiez la langue que vous utilisez pour analyser le 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
user2867288

Je me demande s’il s’agissait d’une question piège posée par un professeur à des étudiants. Pourquoi? Parce qu'il me semble qu'il estIMPOSSIBLEde le faire avec les expressions régulières dans le cas général. 

Votre code (ou celui de qui que ce soit) peut contenir un code JavaScript valide comme ceci:

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

Maintenant, si vous avez une expression rationnelle qui supprime tout Entre une paire de/* et * /, le code Ci-dessus serait cassé, le code exécutable du milieu .__ serait également supprimé.

Si vous essayez de concevoir une expression rationnelle qui ne supprimerait pas les commentaires contenant des guillemets, alors, vous ne pourrez pas supprimer ces commentaires. Cela s’applique aux guillemets simples, doubles et arrières.

Vous ne pouvez pas supprimer (tous) les commentaires avec Regular Expressions en JavaScript, il me semble, Peut-être que quelqu'un peut indiquer comment procéderit pour le cas ci-dessus. 

Ce que vous pouvez faire est de construire un petit analyseur Passe en revue le code, caractère par caractère, et sait quand il se trouve dans une chaîne de caractères et quand it se trouve dans un commentaire et quand il se trouve dans. un commentaire à l'intérieur d'une chaîne et ainsi de suite. 

Je suis sûr que de bons analyseurs syntaxiques JavaScript. Open source peuvent le faire. Peut-être que certains des outils d'empaquetage et de minification .__ peuvent également le faire pour vous.

0
Panu Logic

Pour le commentaire de bloc: https://regex101.com/r/aepSSj/1

Correspond à la barre oblique (le \1) uniquement si la barre oblique est suivie d'un astérisque.

(\/)(?=\*)

peut-être suivi d'un autre astérisque

(?:\*)

suivi du premier groupe de match, ou zéro ou plusieurs fois de quelque chose ... peut-être, sans se rappeler du match mais capturer en tant que groupe.

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

suivi d'un astérisque et du premier groupe

(?:\*)\1

Pour les commentaires de bloc et/ou en ligne: https://regex101.com/r/aepSSj/2

| signifie ou et (?=\/\/(.*)) capture quoi que ce soit après tout //

ou https://regex101.com/r/aepSSj/3 pour capturer la troisième partie également

tous dans: https://regex101.com/r/aepSSj/8

0
Adrian Miranda