【问题标题】:Remove HTML comments with Regex, in Javascript在 Javascript 中使用正则表达式删除 HTML 注释
【发布时间】:2011-08-04 22:09:24
【问题描述】:

我从 Word 生成了一些难看的 HTML,我想从中删除所有 HTML cmets。

HTML 如下所示:

<!--[if gte mso 9]><xml> <o:OfficeDocumentSettings> <o:RelyOnVML/> <o:AllowPNG/> </o:OfficeDocumentSettings> </xml><![endif]--><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:HyphenationZone>21</w:HyphenationZone> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>NO-BOK</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]-->

..我使用的正则表达式就是这个

html = html.replace(/<!--(.*?)-->/gm, "")

但是好像没有匹配,字符串没有变化。

我错过了什么?

【问题讨论】:

标签: javascript regex


【解决方案1】:

正则表达式 /&lt;!--[\s\S]*?--&gt;/g 应该可以工作。

你会在 CDATA 块中杀死 escaping text spans

例如

<script><!-- notACommentHere() --></script>

和格式化代码块中的文字

<xmp>I'm demoing HTML <!-- comments --></xmp>

<textarea><!-- Not a comment either --></textarea>

编辑:

这也不会阻止像中那样引入新的 cmets

<!-<!-- A comment -->- not comment text -->

经过一轮正则表达式会变成

<!-- not comment text -->

如果这是一个问题,您可以转义不属于注释或标签的&lt;(要正确处理很复杂),或者您可以如上所述循环和替换,直到字符串稳定下来。


这是一个正则表达式,它将匹配包括psuedo-comments 在内的 cmets 和根据 HTML-5 规范的未封闭 cmets。 CDATA 部分仅在外部 XML 中被严格允许。这会遇到与上述相同的警告。

var COMMENT_PSEUDO_COMMENT_OR_LT_BANG = new RegExp(
    '<!--[\\s\\S]*?(?:-->)?'
    + '<!---+>?'  // A comment with no body
    + '|<!(?![dD][oO][cC][tT][yY][pP][eE]|\\[CDATA\\[)[^>]*>?'
    + '|<[?][^>]*>?',  // A pseudo-comment
    'g');

【讨论】:

  • 你将如何修改它以仅获取 cmets,并删除 html?
  • @guiomie,我不明白你的目标。请详细解释一下?
  • @MikeSamuel 您的最后一个代码 sn-p 错过了 CDATA 周围的两个反斜杠转义。
  • 请举例说明?
  • 这是一个很好的解决方案,谢谢。我正在尝试对其进行修改以捕获分布在多条线上的 cmets。有什么想法吗?值得提出一个新问题吗?
【解决方案2】:

这是基于Aurielle Perlmann's answer,它支持所有情况(单行、多行、未终止和嵌套的 cmets):

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

https://regex101.com/r/az8Lu6/1

【讨论】:

    【解决方案3】:

    您应该使用/s 修饰符

    html = html.replace(/&lt;!--.*?--&gt;/sg, "")

    在 perl 中测试:

    use strict;
    use warnings;
    
    my $str = 'hello <!--[if gte mso 9]><xml> <o:OfficeDocumentSettings> <o:RelyOnVML/> <o:AllowPNG/> </o:OfficeDocumentSettings> </xml><![endif]--><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:HyphenationZone>21</w:HyphenationZone> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>NO-BOK</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]-->world!';
    
    $str =~ s/<!--.*?-->//sg;
    print $str;
    

    输出:
    hello world!

    【讨论】:

    • JavaScript 没有 s 修饰符。使用[\s\S] 而不是.
    【解决方案4】:

    这也适用于多行 - (&lt;!--.*?--&gt;)|(&lt;!--[\w\W\n\s]+?--&gt;)

    【讨论】:

      【解决方案5】:

      我最近需要做这件事(即从 html 文件中删除所有 cmets)。这些其他答案没有考虑到的一些事情;

      1. 一个 html 文件可以有 css 和 JS 内联,好吧,我至少想去掉这些
      2. 在字符串或正则表达式中的注释语法是完全有效的。 (我的字符串/正则表达式排除模式基于:https://stackoverflow.com/a/23667311/3799617

      TLDR:(我只想要删除所有 cmets 的正则表达式,请)

      /\\\/|\/\s*(?:\\\/|[^\/\*\n])+\/|\\"|"(?:\\"|[^"])*"|\\'|'(?:\\'|[^'])*'|\\`|`(?:\\`|[^`])*`|(\/\/[\s\S]*?$|(?:<!--|\/\s*\*)\s*[\s\S]*?\s*(?:-->|\*\s*\/))/gm
      

      这是一个简单的演示:https://www.regexr.com/5fjlu


      我不讨厌阅读,剩下的给我看:

      我还需要进行各种其他匹配,考虑到有效字符串,其中包含原本显示为有效目标的内容。所以我做了一个类来处理我的各种用途。

      class StringAwareRegExp extends RegExp {
          static get [Symbol.species]() { return RegExp; }
      
          constructor(regex, flags){
              if(regex instanceof RegExp) regex = StringAwareRegExp.prototype.regExpToInnerRegexString(regex);
      
              regex = super(`${StringAwareRegExp.prototype.disqualifyStringsRegExp}(${regex})`, flags);
      
              return regex;
          }
      
          stringReplace(sourceString, replaceString = ''){
              return sourceString.replace(this, (match, group1) => { return group1 === undefined ? match : replaceString; });
          }
      }
      
      StringAwareRegExp.prototype.regExpToInnerRegexString = function(regExp){ return regExp.toString().replace(/^\/|\/[gimsuy]*$/g, ''); };
      Object.defineProperty(StringAwareRegExp.prototype, 'disqualifyStringsRegExp', {
          get: function(){
              return StringAwareRegExp.prototype.regExpToInnerRegexString(/\\\/|\/\s*(?:\\\/|[^\/\*\n])+\/|\\"|"(?:\\"|[^"])*"|\\'|'(?:\\'|[^'])*'|\\`|`(?:\\`|[^`])*`|/);
          }
      });
      

      据此,我创建了另外两个类来磨练我需要的 2 种主要匹配类型:

      class CommentRegExp extends StringAwareRegExp {
          constructor(regex, flags){
              if(regex instanceof RegExp) regex = StringAwareRegExp.prototype.regExpToInnerRegexString(regex);
      
              return super(`\\/\\/${regex}$|(?:<!--|\\/\\s*\\*)\\s*${regex}\\s*(?:-->|\\*\\s*\\/)`, flags);
          }
      }
      
      class StatementRegExp extends StringAwareRegExp {
          constructor(regex, flags){
              if(regex instanceof RegExp) regex = StringAwareRegExp.prototype.regExpToInnerRegexString(regex);
      
              return super(`${regex}\\s*;?\\s*?`, flags);
          }
      }
      

      最后(不管它对谁有用)由此创建的正则表达式:

      const allCommentsRegex = new CommentRegExp(/[\s\S]*?/, 'gm');
      const enableBabelRegex = new CommentRegExp(/enable-?_?\s?babel/, 'gmi');
      const disableBabelRegex = new CommentRegExp(/disable-?_?\s?babel/, 'gmi');
      const includeRegex = new CommentRegExp(/\s*(?:includes?|imports?|requires?)\s+(.+?)/, 'gm');
      const importRegex = new StatementRegExp(/import\s+(?:(?:\w+|{(?:\s*\w\s*,?\s*)+})\s+from)?\s*['"`](.+?)['"`]/, 'gm');
      const requireRegex = new StatementRegExp(/(?:var|let|const)\s+(?:(?:\w+|{(?:\s*\w\s*,?\s*)+}))\s*=\s*require\s*\(\s*['"`](.+?)['"`]\s*\)/, 'gm');
      const atImportRegex = new StatementRegExp(/@import\s*['"`](.+?)['"`]/, 'gm');
      

      最后,如果有人想看看它的使用情况。这是我在其中使用的项目(..我的个人项目始终是 WIP..):https://github.com/fatlard1993/page-compiler

      【讨论】:

        【解决方案6】:
        html = html.replace("(?s)<!--\\[if(.*?)\\[endif\\] *-->", "")
        

        【讨论】:

        • JavaScript 不支持 s 修饰符,也不支持内联修饰符语法,例如 (?s)
        【解决方案7】:

        const regex = /<!--(.*?)-->/gm;
        const str = `You will be able to see this text. <!-- You will not be able to see this text. --> You can even comment out things in <!-- the middle of --> a sentence. <!-- Or you can comment out a large number of lines. --> <div class="example-class"> <!-- Another --> thing you can do is put comments after closing tags, to help you find where a particular element ends. <br> (This can be helpful if you have a lot of nested elements.) </div> <!-- /.example-class -->`;
        const subst = ``;
        
        // The substituted value will be contained in the result variable
        const result = str.replace(regex, subst);
        
        console.log('Substitution result: ', result);

        【讨论】:

        • 请解释您为什么使用m 模式修饰符。
        猜你喜欢
        • 2011-05-02
        • 2019-08-28
        • 1970-01-01
        • 2010-11-08
        • 1970-01-01
        • 1970-01-01
        • 2017-07-26
        • 1970-01-01
        • 2011-01-28
        相关资源
        最近更新 更多