52

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

例如给出以下代码段:

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

这在浏览器中显示为:

Here is my code:

     def some_funtion
       return 'Hello, World!'
     end

当我希望它显示为:

Here is my code:

def some_funtion
 return 'Hello, World!'
end

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

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

4

11 回答 11

24

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

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

在此处输入图像描述

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

在此处输入图像描述

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

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

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

/*!
*** 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 );

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

<script>
    $( function() { $("PRE").prettyPre(); } );
</script>
于 2012-02-19T21:02:05.603 回答
23

缩进注释

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

解决方案

<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>

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

优点

  • 无需 JavaScript
  • 可以静态添加
  • 缩小不会影响缩进并减小文件大小

缺点

  • 需要最少的评论空间
  • 除非使用构建工具,否则不是很优雅

使用节点删除缩进

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

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

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

优点

  • pre编写标签的无缝方式
  • 较小的输出文件大小

缺点

  • 在您的工作流程中需要一个构建步骤
  • 不处理由 CSS 添加的非pre元素white-space: pre

使用 JavaScript 删除缩进

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

优点

  • 可以用white-space: pre

缺点

  • 可以禁用 JavaScript
  • 空格会增加文件大小
于 2015-05-24T03:50:08.783 回答
5

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

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

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

<!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>
于 2011-12-14T13:20:42.947 回答
3

这可以在四行 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>$1');

//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>

于 2015-07-31T20:21:20.247 回答
3

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

鉴于:

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

呈现为:


    def some_funtion
      return 'Hello, World!'
    end

以下香草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;

将导致:

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

并将呈现为:

def some_funtion
  return 'Hello, World!'
end
于 2020-05-19T16:33:15.980 回答
2

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

preserve yield

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

于 2015-04-01T19:12:36.923 回答
2

我决定想出一些比改变方式precode工作更具体的东西。所以我做了一些正则表达式来获取第一个换行符\n(在可能的空格之前 -\s*用于在代码行末尾和换行符之前清理额外的空格(我注意到你的))并找到选项卡或紧随其后的空白字符[\t\s]*(表示制表符、空白字符(0 或更多)并将该值设置为变量。然后在正则表达式替换函数中使用该变量来查找它的所有实例并将其替换为\n(换行符)。因为第二行(pattern设置的位置)没有全局标志(g正则表达式之后的a),它将找到第一个实例\n换行符并将pattern变量设置为该值。因此,在换行符后跟 2 个制表符的情况下,技术上pattern的值\n\t\t将是\npre 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>

于 2015-07-31T21:00:52.267 回答
2

<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>

于 2016-04-20T06:15:25.163 回答
0

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

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

在你的CSS中,

    pre { margin:0 }

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

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

因为每条线都可以工作。

于 2015-04-03T19:16:14.530 回答
0

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

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

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

pre code {
  position: relative;
  left: -95px; // or whatever you want
}
于 2017-11-22T20:48:11.210 回答
-3

pre 标签保留了您在正文中写入时使用的所有空格。通常,如果您不使用 pre 它会正常显示文本...(HTML 将使浏览器忽略那些空格)这里试试这个我使用了段落标签。输出:-

这是我的代码:

def some_function

  返回“你好,世界!”

结尾

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

于 2014-01-29T20:53:00.627 回答