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

发布于 2024-10-11 09:40:23 字数 597 浏览 9 评论 0原文

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

例如,给出以下代码片段:

<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 预标记的当前缩进级别被添加到代码的缩进中。我使用 nanoc 作为静态网站生成器,并且使用 google prettify 来添加语法突出显示。

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

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.

Can anyone offer any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

静谧幽蓝 2024-10-18 09:40: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 的流。您可以使用任何您想要的语言来构建类似的工具。

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>

优点

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

缺点

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

使用 JavaScript 删除缩进

查看此答案以使用 JavaScript 删除缩进

优点

  • 可以使用 < 定位元素code>white-space: pre

缺点

  • 可以禁用 JavaScript
  • 空白会增加文件大小

Indenting With Comments

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

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

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.

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 pre tags
  • Smaller output file size

Disadvantages

  • Requires a build step in your workflow
  • Does not handle non pre elements with white-space: pre added by CSS

Removing Indentation With JavaScript

See this answer to remove indentation with JavaScript

Advantages

  • Possible to target elements with white-space: pre

Disadvantages

  • JavaScript can be disabled
  • White-space adds to the file size
多孤肩上扛 2024-10-18 09:40:23

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

Before

格式被保留,但 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>

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

Before

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

enter image description here

After

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

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.

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

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:

<script>
    $( function() { $("PRE").prettyPre(); } );
</script>
我只土不豪 2024-10-18 09:40:23

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

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

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

<!DOCTYPE html>
<html>
    <head>
        <title>Hello, World!</title>
    </head>
    <body>
        <pre>
            <html>
                <head>
                    <title>Hello World Example</title>
                </head>
                <body>
                    Hello, World!
                </body>
            </html>
        </pre>
        <pre>
            class HelloWorld
            {
                public static int Main(String[] args)
                {
                    Console.WriteLine(&quot;Hello, World!&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>

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 outerHTML is 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).

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

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>
            <html>
                <head>
                    <title>Hello World Example</title>
                </head>
                <body>
                    Hello, World!
                </body>
            </html>
        </pre>
        <pre>
            class HelloWorld
            {
                public static int Main(String[] args)
                {
                    Console.WriteLine(&quot;Hello, World!&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>
紫竹語嫣☆ 2024-10-18 09:40:23

这可以通过四行 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>

This can be done in four lines of 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>

岁吢 2024-10-18 09:40:23

如果您同意更改元素的 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

If you're okay with changing the innerHTML of the element:

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:

// 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
云淡月浅 2024-10-18 09:40:23

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

preserve yield

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

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

preserve yield

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

海拔太高太耀眼 2024-10-18 09:40:23

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

I decided to come up with something more concrete than changing the way pre or code work. 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 pattern gets set) doesn't have the global flag (a g after the regex), it will find the first instance of the \n newline character and set the pattern variable to that value. So in the case of a newline, followed by 2 tab characters, the value of pattern will technically be \n\t\t, which will be replaced where every \n character is found in that pre code element (since it's running through the each function) and replaced with \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>

梦太阳 2024-10-18 09:40:23
<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>

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

放我走吧 2024-10-18 09:40:23

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

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

for every line 就可以了。

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,

    pre { margin:0 }

In vim, writing your code normally and then executing:

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

for each line would work.

ぶ宁プ宁ぶ 2024-10-18 09:40:23

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

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

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

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

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.

pre code {
  position: relative;
  left: -95px; // or whatever you want
}
旧时模样 2024-10-18 09:40:23

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

这是我的代码:

def some_function

  return 'Hello, World!'

结束

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

The pre tag preserves all the white spaces you have used while writing in the body. Where as normally if you do not use pre it will display the text normally...(HTML will make the browser to neglect those white spaces) Here try this I have used the paragraph tag.
Output:-

Here is my code:

def some_function

  return 'Hello, World!'

end

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文