如何保留 HTML <pre> 标签中包含的文本的空白缩进,不包括文档中 <pre> 标签的当前缩进级别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4631646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 06:02:20  来源:igfitidea点击:

How to preserve whitespace indentation of text enclosed in HTML <pre> tags excluding the current indentation level of the <pre> tag in the document?

htmlwhitespaceindentationpre

提问by Michael Barton

I'm trying to display my code on a website but I'm having problems preserving the whitespace indentation correctly.

我正在尝试在网站上显示我的代码,但我在正确保留空白缩进方面遇到了问题。

For instance given the following snippet:

例如,给出以下代码段:

<html>
 <body>
   Here is my code:
   <pre>
     def some_funtion
       return 'Hello, World!'
     end
   </pre>
 <body>
</html>

This is displayed in the browser as:

这在浏览器中显示为:

Here is my code:

     def some_funtion
       return 'Hello, World!'
     end

When I would like it displayed as:

当我希望它显示为:

Here is my code:

def some_funtion
 return 'Hello, World!'
end

The difference is that that current indentation level of the HTML pre tag is being added to the indentation of the code. I'm using nanoc as a static website generator and I'm using google prettify to also add syntax highlighting.

不同之处在于 HTML pre 标记的当前缩进级别被添加到代码的缩进中。我使用 nanoc 作为静态网站生成器,并且使用 google prettify 还添加了语法突出显示。

Can anyone offer any suggestions?

任何人都可以提供任何建议吗?

回答by Tim Medora

PREis intended to preserve whitespace exactly as it appears (unless altered by white-spacein CSS, which doesn't have enough flexibility to support formatting code).

PRE旨在完全保留其出现的空白(除非white-space在 CSS 中进行了更改,因为 CSS 没有足够的灵活性来支持格式化代码)。

Before

Formatting is preserved, but so is all the indentation outside of the PREtag. It would be nice to have whitespace preservation that used the location of the tag as a starting point.

格式被保留,但PRE标签外的所有缩进也被保留。保留使用标签位置作为起点的空白会很好。

enter image description here

在此处输入图片说明

After

Contents are still formatted as declared, but the extraneous leading whitespace caused by the position of the PREtag within the document is removed.

内容仍然按照声明的格式进行格式化,但PRE删除了由文档中标签位置引起的无关的前导空格。

enter image description here

在此处输入图片说明

I have come up with the following plugin to solve the issue of wanting to remove superfluous whitespace caused by the indentation of the document outline. This code uses the first line inside the PRE tag to determine how much it has been indented purely due to the indentation of the document.

我想出了以下插件来解决想要删除由于文档大纲缩进引起的多余空格的问题。这段代码使用 PRE 标签内的第一行来确定纯粹由于文档的缩进而缩进了多少。

This code works in IE7, IE8, IE9, Firefox, and Chrome. I have tested it briefly with the Prettifylibrary to combine the preserved formatting with pretty printing. Make sure that the first line inside the PREactually represents the baseline level of indenting that you want to ignore (or, you can modify the plugin to be more intelligent).

此代码适用于 IE7、IE8、IE9、Firefox 和 Chrome。我已经使用Prettify库对其进行了简要测试,以将保留的格式与漂亮的打印相结合。确保里面的第一行PRE实际上代表了您要忽略的缩进的基线级别(或者,您可以修改插件以使其更智能)。

This is rough code. If you find a mistake or it does not work the way you want, please fix/comment; don't just downvote. I wrote this code to fix a problem that I was having and I am actively using it so I would like it to be as solid as possible!

这是粗略的代码。如果您发现错误或无法按您想要的方式工作,请修复/评论;不要只是投反对票。我写了这段代码来解决我遇到的一个问题,我正在积极使用它,所以我希望它尽可能可靠!

/*!
*** prettyPre ***/

(function( $ ) {

    $.fn.prettyPre = function( method ) {

        var defaults = {
            ignoreExpression: /\s/ // what should be ignored?
        };

        var methods = {
            init: function( options ) {
                this.each( function() {
                    var context = $.extend( {}, defaults, options );
                    var $obj = $( this );
                    var usingInnerText = true;
                    var text = $obj.get( 0 ).innerText;

                    // some browsers support innerText...some don't...some ONLY work with innerText.
                    if ( typeof text == "undefined" ) {
                        text = $obj.html();
                        usingInnerText = false;
                    }

                    // use the first line as a baseline for how many unwanted leading whitespace characters are present
                    var superfluousSpaceCount = 0;
                    var currentChar = text.substring( 0, 1 );

                    while ( context.ignoreExpression.test( currentChar ) ) {
                        currentChar = text.substring( ++superfluousSpaceCount, superfluousSpaceCount + 1 );
                    }

                    // split
                    var parts = text.split( "\n" );
                    var reformattedText = "";

                    // reconstruct
                    var length = parts.length;
                    for ( var i = 0; i < length; i++ ) {
                        // cleanup, and don't append a trailing newline if we are on the last line
                        reformattedText += parts[i].substring( superfluousSpaceCount ) + ( i == length - 1 ? "" : "\n" );
                    }

                    // modify original
                    if ( usingInnerText ) {
                        $obj.get( 0 ).innerText = reformattedText;
                    }
                    else {
                        // This does not appear to execute code in any browser but the onus is on the developer to not 
                        // put raw input from a user anywhere on a page, even if it doesn't execute!
                        $obj.html( reformattedText );
                    }
                } );
            }
        }

        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
        }
        else if ( typeof method === "object" || !method ) {
            return methods.init.apply( this, arguments );
        }
        else {
            $.error( "Method " + method + " does not exist on jQuery.prettyPre." );
        }
    }
} )( jQuery );

This plugin can then be applied using a standard jQuery selector:

然后可以使用标准的 jQuery 选择器应用此插件:

<script>
    $( function() { $("PRE").prettyPre(); } );
</script>

回答by Dale

Indenting With Comments

用注释缩进

Since browsers ignore comments, you can use them to indent your pretag contents.

由于浏览器会忽略注释,您可以使用它们来缩进pre标签内容。

Solution

解决方案

<html>
  <body>
    <main>
      Here is my code with hack:
      <pre>
<!-- -->def some_function
<!-- -->  return 'Hello, World!'
<!-- -->end
      </pre>
      Here is my code without hack:
      <pre>
        def some_function
          return 'Hello, World!'
        end
      </pre>
    </main>
  <body>
</html>

NOTE: a main wrapper was added to provide enough space for the comments.

注意:添加了一个主要的包装器来为评论提供足够的空间。

Advantages

好处

  • No JavaScript required
  • Can be added statically
  • Minification won't affect the indentation and reduces file size
  • 不需要 JavaScript
  • 可以静态添加
  • 缩小不会影响缩进并减小文件大小

Disadvantages

缺点

  • Requires a minimum amount of space for the comments
  • Not very elegant unless build tools are used
  • 需要最少的评论空间
  • 除非使用构建工具,否则不是很优雅

Removing Indentation With Node

删除节点的缩进

A better solution is to remove the leading white-space using either your build process or back-end rendering process. If you are using node.js, then you can use a stream I wrote called predentation. You can use any language you want to build a similar tool.

更好的解决方案是使用您的构建过程或后端渲染过程去除前导空白。如果您使用的是 node.js,那么您可以使用我编写的名为predentation的流。你可以使用任何你想要的语言来构建一个类似的工具。

Before

<html>
 <body>
   Here is my code:
   <pre>
     def some_function
       return 'Hello, World!'
     end
   </pre>
 </body>
</html>

After

<html>
 <body>
   Here is my code:
   <pre>
def some_function
  return 'Hello, World!'
end
   </pre>
 </body>
</html>

Advantages

好处

  • Seamless way to write pretags
  • Smaller output file size
  • 编写pre标签的无缝方式
  • 更小的输出文件大小

Disadvantages

缺点

  • Requires a build step in your workflow
  • Does not handle non preelements with white-space: preadded by CSS
  • 在您的工作流程中需要一个构建步骤
  • 不处理由 CSS 添加的非pre元素white-space: pre

Removing Indentation With JavaScript

使用 JavaScript 删除缩进

See this answer to remove indentation with JavaScript

请参阅此答案以使用 JavaScript 删除缩进

Advantages

好处

  • Possible to target elements with white-space: pre
  • 可以定位元素 white-space: pre

Disadvantages

缺点

  • JavaScript can be disabled
  • White-space adds to the file size
  • 可以禁用 JavaScript
  • 空白会增加文件大小

回答by user247702

Managed to do this with JavaScript. It works in Internet Explorer 9 and Chrome 15, I haven't tested older versions. It should work in Firefox 11 when support for outerHTMLis added (see here), meanwhile there are some custom implementations available on the web. An excercise for the reader is to get rid of trailing indentation (until I make time to finish it and update this answer).

设法用 JavaScript 做到了这一点。它适用于 Internet Explorer 9 和 Chrome 15,我还没有测试过旧版本。outerHTML添加对 的支持后,它应该可以在 Firefox 11 中工作(请参阅此处),同时网络上有一些自定义实现可用。读者的一个练习是摆脱尾随缩进(直到我有时间完成它并更新这个答案)。

I'll also mark this as community wiki for easy editing.

我还将将此标记为社区 wiki,以便于编辑。

Please note that you'll have to reformat the example to use tabs as indentation, or change the regex to work with spaces.

请注意,您必须重新格式化示例以使用制表符作为缩进,或者更改正则表达式以使用空格。

<!DOCTYPE html>
<html>
    <head>
        <title>Hello, World!</title>
    </head>
    <body>
        <pre>
            &lt;html&gt;
                &lt;head&gt;
                    &lt;title&gt;Hello World Example&lt;/title&gt;
                &lt;/head&gt;
                &lt;body&gt;
                    Hello, World!
                &lt;/body&gt;
            &lt;/html&gt;
        </pre>
        <pre>
            class HelloWorld
            {
                public static int Main(String[] args)
                {
                    Console.WriteLine(&amp;quot;Hello, World!&amp;quot;);
                    return 0;
                }
            }
        </pre>
        <script language="javascript">
            var pre_elements = document.getElementsByTagName('pre');

            for (var i = 0; i < pre_elements.length; i++)
            {
                var content = pre_elements[i].innerHTML;

                var tabs_to_remove = '';
                while (content.indexOf('\t') == '0')
                {
                  tabs_to_remove += '\t';
                  content = content.substring(1);
                }

                var re = new RegExp('\n' + tabs_to_remove, 'g');
                content = content.replace(re, '\n');
                pre_elements[i].outerHTML = '<pre>' + content + '</pre>';
            }
        </script>
    </body>
</html>

回答by Rick Hitchcock

This can be done in four lines of JavaScript:

这可以在四行 JavaScript 中完成:

var pre= document.querySelector('pre');

//insert a span in front of the first letter.  (the span will automatically close.)
pre.innerHTML= pre.textContent.replace(/(\w)/, '<span>');

//get the new span's left offset:
var left= pre.querySelector('span').getClientRects()[0].left;

//move the code to the left, taking into account the body's margin:
pre.style.marginLeft= (-left + pre.getClientRects()[0].left)+'px';
 <body>
   Here is my code:
   <pre>
     def some_funtion
       return 'Hello, World!'
     end
   </pre>
 <body>

回答by ctwheels

I decided to come up with something more concrete than changing the way preor codework. So I made some regex to get the first newline character \n(preceded with possible whitespace - the \s*is used to cleanup extra whitespace at the end of a line of code and before the newline character (which I noticed yours had)) and find the tab or whitespace characters following it [\t\s]*(which means tab character, whitespace character (0 or more) and set that value to a variable. That variable is then used in the regex replace function to find all instances of it and replace it with \n(newline). Since the second line (where patterngets set) doesn't have the global flag (a gafter the regex), it will find the first instance of the \nnewline character and set the patternvariable to that value. So in the case of a newline, followed by 2 tab characters, the value of patternwill technically be \n\t\t, which will be replaced where every \ncharacter is found in that pre codeelement (since it's running through the each function) and replaced with \n

我决定想出一些比改变方式precode工作更具体的方法。所以我做了一些正则表达式来获取第一个换行符\n(前面有可能的空格 -\s*用于清除代码行末尾和换行符之前的额外空格(我注意到你有))并找到选项卡或跟在它后面的空白字符[\t\s]*(这意味着制表符、空白字符(0 或更多)并将该值设置为一个变量。然后在正则表达式替换函数中使用该变量来查找它的所有实例并将其替换为\n(换行符)。由于第二行(pattern设置的地方)没有全局标志(g在正则表达式之后),它将找到第一个实例\n换行符并将pattern变量设置为该值。因此,在一新行的情况下,接着2个制表符,的值pattern将是技术上\n\t\t,其中,每其将被替换\n的字符在所发现pre code元件(因为它是通过每个功能运行)中,用替换\n

$("pre code").each(function(){
    var html = $(this).html();
    var pattern = html.match(/\s*\n[\t\s]*/);
    $(this).html(html.replace(new RegExp(pattern, "g"),'\n'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
    Here is some code:

    <pre><code>
        Here is some fun code!
        More code
          One tab
            One more tab
            
            Two tabs and an extra newline character precede me
    </code></pre>
</body>

回答by u5649918

<script>
    $("pre[name='pre']").each(function () {
        var html = $(this).html()
        var blankLen = (html.split('\n')[0].match(/^\s+/)[0]).length
        $(this).html($.trim(html.replace(eval("/^ {" + blankLen + "}/gm"), "")))
    })
</script>
<div>
 <pre name="pre">
  1
   2
    3
 </pre>
</div>

回答by Michael Barton

I also found that if you're using haml you can use the preservemethod. For example:

我还发现,如果您使用的是haml,则可以使用该preserve方法。例如:

preserve yield

This will preserve the whitespace in the produced yieldwhich is usually markdown containing the code blocks.

这将保留生成的空白,yield通常是包含代码块的降价。

回答by Paul Robert

This is cumbersome, but it works if code folding is important to you:

这很麻烦,但如果代码折叠对您很重要,它会起作用:

        <pre>def some_funtion</pre>
        <pre>    return 'Hello, World!'</pre>
        <pre>end</pre>

In your css,

在你的 css 中,

    pre { margin:0 }

In vim, writing your code normally and then executing:

在vim中,正常编写代码然后执行:

    :s/\t\t\([^\n]\+\)/<pre><\/pre>/

for each line would work.

对于每一行都会起作用。

回答by Sk?ggiga Mannen

If you are using this on a code block like:

如果您在代码块上使用它,例如:

<pre>
  <code>
    ...
  </code>
</pre>

You can just use css like this to offset that large amount of white space in the front.

您可以像这样使用 css 来抵消前面的大量空白。

pre code {
  position: relative;
  left: -95px; // or whatever you want
}

回答by Amir

If you're okay with changing the innerHTMLof the element:

如果您可以更改innerHTML元素的 :

Given:

鉴于:

<pre>
  <code id="the-code">
    def some_funtion
      return 'Hello, World!'
    end
  </code
</pre>

Which renders as:

呈现为:


    def some_funtion
      return 'Hello, World!'
    end

The following vanilla JS:

以下香草JS:

// get block however you want.
var block = document.getElementById("the-code");

// remove leading and trailing white space.
var code = block.innerHTML
                .split('\n')
                .filter(l => l.trim().length > 0)
                .join('\n');

// find the first non-empty line and use its
// leading whitespace as the amount that needs to be removed
var firstNonEmptyLine = block.textContent
                             .split('\n')
                             .filter(l => l.trim().length > 0)[0];

// using regex get the first capture group
var leadingWhiteSpace = firstNonEmptyLine.match(/^([ ]*)/);

// if the capture group exists, then use that to
// replace all subsequent lines.
if(leadingWhiteSpace && leadingWhiteSpace[0]) {
  var whiteSpace = leadingWhiteSpace[0];
  code = code.split('\n')
             .map(l => l.replace(new RegExp('^' + whiteSpace + ''), ''))
             .join('\n');
}

// update the inner HTML with the edited code
block.innerHTML = code;

Will result in:

会导致:

<pre>
  <code id="the-code">def some_funtion
  return 'Hello, World!'
end</code>
</pre>

And will render as:

并将呈现为:

def some_funtion
  return 'Hello, World!'
end