多行字符串,不会破坏缩进

时间:2014-09-18 23:29:45

标签: javascript ecmascript-6 template-strings

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

Allen Wirfs-Brock’s post包含一个代码示例:

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以删除用于缩进的空格?

6 个答案:

答案 0 :(得分:14)

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

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中成功测试了它:

enter image description here

答案 1 :(得分:14)

2016年回答dedent-js package将处理此问题。注意'dedent-js'包实际上适用于制表符和空格,'dedent'在选项卡上失败:

var dedent = require('dedent-js');

var text = dedent(`
  <div>
    <span>OK</span>
    <div>
      <div></div>
    </div>
  </div>
`);

将删除每行上的前进空格和前导回车。它还拥有更多用户,问题跟踪器,并且比Stack Overflow的复制更容易更新!

答案 2 :(得分:2)

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

const MSG = (`Line 1
          line 2
          line 3`).replace(/  +/g, '');
// outputs
/*
Line 1
line 2
line 3
*/

答案 3 :(得分:2)

如何定义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 template literals可以用标签(在本示例中为dontIndent)调用。标签被定义为函数,并以模板文字作为参数进行调用,因此我们定义了dontIndent()函数。模板文字作为数组中的参数传递,因此我们使用表达式('' + str)将数组内容转换为字符串。然后,我们可以使用/(\n)\s+/g.replace()之类的正则表达式,在所有出现换行符的地方都紧跟空格,然后仅换行符来达到OP的目的。

答案 4 :(得分:1)

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

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

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-literals 安装,并通过将 dedent-template-literals 作为 Babel configurationplugins 数组的第一个元素来使用。 Further information can be found on the README

答案 5 :(得分:0)

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

存在许多NPM模块可以做到这一点,它们将覆盖许多难以应付的极端情况。主要的两个是:

dedent,每周下载400万次,最近更新于4年前
dedent npm badge, with the above statistics

endent,每周下载2.5千,于4个月前更新
endent npm badge, with the above statistics