web-dev-qa-db-ja.com

JavaScriptコメントの一致/置換用の正規表現(複数行とインラインの両方)

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に似たコメントをすべて削除するRegExパターンが必要です。

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

また、これらの条件付きHTMLコメントは、さまざまなJavaScriptソースにあります。

ありがとう。

38
metaforce

これを試して、

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

動作するはずです:) enter image description here

18
abi1964

注: 正規表現はレクサーでもパーサーでもありません 。文字列から解析された奇妙にネストされたコメントが必要なEdgeの奇妙なケースがある場合は、パーサーを使用してください。他の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

使用ケースの失敗:この正規表現が失敗するエッジのケースがいくつかあります。これらのケースの進行中のリストは this public Gist に文書化されています。他のケースが見つかった場合は、要旨を更新してください。

...また、alsoを削除したい場合は<!-- html comments --> これを使って:

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

(オリジナル-歴史的参照のみ)

// DO NOT USE THIS - SEE ABOVE
/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm
68
Ryan Wheale

私はtogethorに似たようなことをする必要がある表現を入れてきました。
完成品は次のとおりです。

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

2番目の部分は、/ * * /で区切られた複数行のコメントに一致します

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

3番目の部分は、行の任意の場所から始まる単一行のコメントに一致します

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

4番目から6番目の部分は、正規表現リテラル内のすべてに一致します
これは、正規表現呼び出しの前後にある等号またはリテラルに依存しています。

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

もともと忘れていた7番目は、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 '';
}

これは、引用符で囲まれた文字列テキストでキャプチャされたものと、正規表現リテラルで見つかったものをそのまま返しますが、すべてのコメントキャプチャに対して空の文字列を返します。

私はこれが過剰であり、維持するのがかなり難しいことを知っていますが、今のところうまくいくようです。

6
wolffer-east

これはほとんどすべての場合に機能します。

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コンパイラ 用に作成しました。

http://github.com/aMarCruz/jspreproc を参照してください

2
aMarCruz

少しシンプルに-

これは複数行でも機能します-(<!--.*?-->)|(<!--[\w\W\n\s]+?-->)

enter image description here

1

単純で単純なJS正規表現では、次のようになります。

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

これは元の質問に大して役に立たないが、誰かの助けになるかもしれない。

@Ryan Whealeの回答に基づいて、これが包括的なキャプチャとして機能し、一致により文字列リテラル内で見つかったものが除外されることを確認しました。

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

最後のグループ(他のすべては破棄されます)は、Ryanの回答に基づいています。例 ここ

これは、コードが適切に構造化され、有効なjavascriptであると想定しています。

注:これは、javascriptエンジンのヒューリスティックに応じて回復可能な場合と回復できない場合のある、構造の悪いコードではテストされていません。

注:これは有効なjavascript <ES6を保持する必要がありますが、ES6では 複数行文字列リテラル を使用できます。この場合、この正規表現はほぼ確実に壊れますが、その場合はテストされていません。


ただし、正規表現リテラル内のコメントのように見えるものと一致させることは可能です(上記の例のコメント/結果を参照)。

Mike Samuel で参照されているように、es5-lexer here および here から抽出された次の包括的なキャプチャを使用して、すべての正規表現リテラルを置き換えた後、上記のキャプチャを使用します この質問 に対する回答

/(?:(?: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 も参照してください。

1
Nolo

下のリンクをクリックすると、正規表現で記述されたコメント削除スクリプトが見つかります。

これらは、mootoolsとJoomlaおよびdrupalおよびその他のcms Webサイトで動作します。800.000行のコードとコメントでテストしました。正常に動作します。 like(abc(/nn/( '/xvx/') ) "// testing line")とコロンの間にあるコメントとそれらを保護します。23-01-2016 ..!これはコメントを含むコードです!!!!!

ここをクリック

1
John Smith

私も簡単な正規表現ソリューションを探していましたが、100%動作する答えはありませんでした。ほとんどの場合、文字列リテラル内で検出されたコメントが原因で、それぞれが何らかの方法でソースコードを壊してしまいます。例えば。

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

になる

var string = "https:

グーグルから来た人たちのために、私は正規表現ではできなかったことを実現する短い関数を(Javascriptで)書きました。 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

2019年:

ここでの答えはすべて良くありませんでした。だから私はもっと良いものを書いて、試してみてください:

function striptComment(code){
 return code
 // remove multi line comment /* */
 .replace(/(\t*\/\*[\s\S]*?\*(\n?)\/)/gm, '')
 // remove one line comment //
 // there is some hack here, to skip "'//'" or http://..' 
 .replace(/([\t ]+(?!"'.*)\/\/[\s\S]*?(?=\n))/gm, '')
 // remove html comment <!-- --> 
 .replace(/(\t*<!--[\s\S]*?-->\n?)/gm, '')
 // bonus:
 // encode " and ' in the string (' -> \' ..)
 .replace(/(['"])/gm,"\\$1")
 // clean new line and tabs */
 .replace(/[\n\t\r]+/gm,"")
 ;
}
// example
striptComment(striptComment.toString())
// function striptComment(code){ return code .replace(/(\t*\/\*[\s\S]*?\*(\n?)\/)/gm, \'\') .replace(/([\t ]+(?!\"\'.*)\/\/[\s\S]*?(?=\n))/gm, \'\') .replace(/(\t*\n?)/gm, \'\') .replace(/([\'\"])/gm,\"\\$1\") .replace(/[\n\t\r]+/gm,\"\") ;}

0
pery mimon

これは教授が学生に与えたトリックの質問だったのだろうか。どうして?私にはそう思われるので、通常の場合、正規表現でこれを行うのは[〜#〜] impossible [〜#〜]です。

あなた(またはコードの人)には、次のような有効なJavaScriptを含めることができます。

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

これで、/ *と* /のペアの間のすべてを削除する正規表現がある場合、上記のコードが破損し、中央の実行可能コードも削除されます。

引用符を含むコメントを削除しない正規表現を考案しようとすると、そのようなコメントは削除できません。これは、単一引用符、二重引用符、および逆引用符に適用されます。

JavaScriptの正規表現を使用して(すべての)コメントを削除することはできません。どうやら、上記の場合の方法を誰かが指摘できるようです。

あなたができることは、文字ごとにコードを調べ、それが文字列の中にあるとき、それがコメントの中にあるとき、そしてそれが文字列の中のコメントの中にあるときなどを知っている小さなパーサーを構築することです。

これを実行できる優れたオープンソースJavaScriptパーサーがあると確信しています。たぶん、いくつかのパッケージ化ツールと縮小ツールがあなたのためにこれを行うことができます。

0
Panu Logic

ブロックコメントの場合: 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

0
Adrian Miranda