68

根据这个 esdiscuss 讨论,在 ECMAScript 6 中可以定义多行字符串,而不必将字符串的后续行放在行的开头。

Allen Wirfs-Brock 的帖子包含一个代码示例:

var a = dontIndent
        `This is a template string.
         Even though each line is indented to keep the
         code neat and tidy, the white space used to indent
         is not in the resulting string`;

有人可以解释如何实现这一目标吗?如何定义这个dontIndent东西以删除用于缩进的空格?

4

6 回答 6

40

2020 年回答:尽管TC39 讨论了添加一个新的模板文字来处理缩进,但 JS 标准库中仍然没有内置任何东西来处理去凹痕。您目前有 2 个选择:

  1. endent和dedent -js包将处理这个问题。请注意,该dedent-js包实际上适用于制表符和空格,dedent是一个单独的包并且在制表符上失败:
    var dedent = require('dedent-js');
    var text = dedent(`
      <div>
        <span>OK</span>
        <div>
          <div></div>
        </div>
      </div>
    `);

将去掉每行前面的空格和前导的回车符。它还拥有更多用户、问题跟踪器,并且比从 Stack Overflow 复制粘贴更容易更新!

  1. 不要缩进长行,而是使用将长行显示为 indented 的编辑器。例如,vsCode - 您可以简单地使用长行,而不是缩进任何内容,并在长字符串中包含回车。vsCode 将显示它们缩进。下面的字符串没有缩进 - 第二行The empty export...紧跟在回车之后,但显示为缩进。

在此处输入图像描述

于 2016-08-18T13:30:17.053 回答
18

此功能是通过定义自定义函数然后将其用作标记来实现的(dontIndent如上)。代码打击来自Zenparsing 的要点

function dedent(callSite, ...args) {

    function format(str) {

        let size = -1;

        return str.replace(/\n(\s+)/g, (m, m1) => {

            if (size < 0)
                size = m1.replace(/\t/g, "    ").length;

            return "\n" + m1.slice(Math.min(m1.length, size));
        });
    }

    if (typeof callSite === "string")
        return format(callSite);

    if (typeof callSite === "function")
        return (...args) => format(callSite(...args));

    let output = callSite
        .slice(0, args.length + 1)
        .map((text, i) => (i === 0 ? "" : args[i - 1]) + text)
        .join("");

    return format(output);
}

我已经在 Firefox Nightly 中成功测试了它:

在此处输入图像描述

于 2014-09-19T15:27:19.820 回答
18

您也可以只对双空格进行字符串替换(假设您的缩进使用空格,而不是制表符)。显然,您的实际字符串中的任何双空格都会被删除,但在大多数情况下,这应该没问题。

const MSG = (`Line 1
          line 2
          line 3`).replace(/  +/g, '');
// outputs
/*
Line 1
line 2
line 3
*/
于 2018-12-05T00:09:38.403 回答
8

如何定义这个dontIndent东西以删除用于缩进的空格?

我想这样的事情对于许多情况(包括 OP)应该就足够了:

function dontIndent(str){
  return ('' + str).replace(/(\n)\s+/g, '$1');
}

此片段中的演示代码:

var a = dontIndent
        `This is a template string.
         Even though each line is indented to keep the
         code neat and tidy, the white space used to indent
         is not in the resulting string`;

console.log(a);
         
function dontIndent(str){
  return ('' + str).replace(/(\n)\s+/g, '$1');
}

解释

JavaScript 模板字面量可以用一个标签来调用,在这个例子中是dontIndent. 标签被定义为函数,并以模板文字作为参数调用,因此我们定义了一个dontIndent()函数。模板文字作为数组中的参数传递,因此我们使用表达式('' + str)将数组内容转换为字符串。然后,我们可以使用正则表达式,如/(\n)\s+/g所有.replace()出现的换行符后跟空格,只用换行符来实现OP的目的。

于 2020-08-10T19:06:24.317 回答
1

所有现有答案的问题是,它们是运行时解决方案。也就是说,他们采用多行模板文字并在程序执行时通过函数运行它,以消除前导空格。这是这样做的“错误方式”,因为这个操作应该在编译时完成。原因是,在这个操作中没有任何东西需要运行时信息,所有需要的信息在编译时都是已知的。

为了在编译时完成,我编写了一个名为 Dedent Template Literals 的 Babel 插件。基本上它的工作原理如下:

const httpRFC = `                Hypertext Transfer Protocol -- HTTP/1.1

                 Status of this Memo

                    This document specifies an Internet standards track protocol for the
                    Internet community, and requests discussion and suggestions for
                    improvements.  Please refer to the current edition of the "Internet
                    Official Protocol Standards" (STD 1) for the standardization state
                    and status of this protocol.  Distribution of this memo is unlimited.

                 Copyright Notice

                    Copyright (C) The Internet Society (1999).  All Rights Reserved.`;

console.log(httpRFC);

将打印:

                Hypertext Transfer Protocol -- HTTP/1.1

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

插值工作也没有任何问题。此外,如果您在模板文字的开始反引号之后的第一列之前开始一行,插件将抛出错误,显示错误的位置。如果以下文件位于src/httpRFC.js您的项目下:

const httpRFC = `                Hypertext Transfer Protocol -- HTTP/1.1

                 Status of this Memo

                    This document specifies an Internet standards track protocol for the
                    Internet community, and requests discussion and suggestions for
                    improvements.  Please refer to the current edition of the "Internet
                    Official Protocol Standards" (STD 1) for the standardization state
                    and status of this protocol.  Distribution of this memo is unlimited.

                Copyright Notice

                    Copyright (C) The Internet Society (1999).  All Rights Reserved.`;

console.log(httpRFC);

转译时会出现以下错误:

Error: <path to your project>/src/httpRFC.js: LINE: 11, COLUMN: 17. Line must start at least at column 18.
    at PluginPass.dedentTemplateLiteral (<path to your project>/node_modules/babel-plugin-dedent-template-literals/index.js:39:15)
    at newFn (<path to your project>/node_modules/@babel/traverse/lib/visitors.js:175:21)
    at NodePath._call (<path to your project>/node_modules/@babel/traverse/lib/path/context.js:55:20)
    at NodePath.call (<path to your project>/node_modules/@babel/traverse/lib/path/context.js:42:17)
    at NodePath.visit (<path to your project>/node_modules/@babel/traverse/lib/path/context.js:92:31)
    at TraversalContext.visitQueue (<path to your project>/node_modules/@babel/traverse/lib/context.js:116:16)
    at TraversalContext.visitSingle (<path to your project>/node_modules/@babel/traverse/lib/context.js:85:19)
    at TraversalContext.visit (<path to your project>/node_modules/@babel/traverse/lib/context.js:144:19)
    at Function.traverse.node (<path to your project>/node_modules/@babel/traverse/lib/index.js:82:17)
    at NodePath.visit (<path to your project>/node_modules/@babel/traverse/lib/path/context.js:99:18) {
  code: 'BABEL_TRANSFORM_ERROR'
}

如果您使用制表符(并且只有制表符)进行缩进并使用空格(并且只有空格)进行对齐,它也适用于制表符。

它可以通过运行来安装,也可以通过npm install --save-dev babel-plugin-dedent-template-literalsBabel 配置中作为数组dedent-template-literals的第一个元素来使用。更多信息可以在 README 中找到plugins

于 2021-02-05T00:57:46.580 回答
1

正如Šime Vidas所说,函数可以用作标签,只需将其放在模板字符串的前面即可调用。

存在许多 NPM 模块来执行此操作,并且将涵盖许多您自己难以涵盖的边缘情况。主要的两个是:

dedent,每周 400 万次下载,上次更新时间为 4 年前
dedent npm 徽章,具有上述统计信息

endent,每周 250 次下载,4 个月前更新
endent npm 徽章,具有上述统计信息

于 2020-08-10T10:21:01.240 回答