admin管理员组文章数量:1134247
According to this esdiscuss discussion, it is possible in ECMAScript 6 to define multiline strings without having to place subsequent lines of the string at the very beginning of the line.
Allen Wirfs-Brock’s post contains a code example:
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`;
Could someone explain how this can be achieved? How to define this dontIndent
thing in order to remove the whitespace used for indentation?
According to this esdiscuss discussion, it is possible in ECMAScript 6 to define multiline strings without having to place subsequent lines of the string at the very beginning of the line.
Allen Wirfs-Brock’s post contains a code example:
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`;
Could someone explain how this can be achieved? How to define this dontIndent
thing in order to remove the whitespace used for indentation?
10 Answers
Reset to default 58 +1002020 answer: there is still nothing built into the JS stdlib to handle de-denting long lines, although TC39 has discussed adding a new template literal that handles indentation. You have 2 options presently:
- The endent and dedent-js packages will handle this. Note the
dedent-js
package actually works with both tabs and spaces.
var dedent = require('dedent-js');
var text = dedent(`
<div>
<span>OK</span>
<div>
<div></div>
</div>
</div>
`);
Will strip out the proceeding whitespace on each line and the leading carriage return. It also has more users, an issue tracker, and is more easily updated than copypasting from Stack Overflow!
Note: dedent
is a separate package from dedent-js
and dedent
fails on tabs.
- Don't indent long lines, but use an editor that shows long lines as indented. Eg, vsCode - you can simply use long lines, not indent anything, and include carriage returns in a long string. vsCode will show them indented. The string below has no indentation - the second line
The empty export...
is immediately after the carriage return, but shows up as indented.
You can also just do a string replace for double spaces (assuming your indentation uses spaces, not tabs). Obviously any double spaces in your actual string would be removed, but for most cases this should be ok.
const MSG = (`Line 1
line 2
line 3`).replace(/ +/g, '');
// outputs
/*
Line 1
line 2
line 3
*/
This feature is implemented by defining a custom function and then using it as a tag (dontIndent
above). The code blow is from 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);
}
I've successfully tested it in Firefox Nightly:
How to define this
dontIndent
thing in order to remove the whitespace used for indentation?
I suppose something like this should suffice for many cases (including the OP):
function dontIndent(str){
return ('' + str).replace(/(\n)\s+/g, '$1');
}
Demo code in this snippet:
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');
}
Explanation
JavaScript template literals can be called with a tag, which in this example is dontIndent
. Tags are defined as functions, and are called with the template literal as an argument, so we define a dontIndent()
function. The template literal is passed as an argument in an array, so we use the expression ('' + str)
to cast the array content to a string. Then, we can use a regular expression like /(\n)\s+/g
to .replace()
all occurrences of line breaks followed by white space with only the line break to achieve the aim of the OP.
The problem with all the existing answers is, they are run-time solutions. That is, they take the multi-line template literal and run it through a function, while the program is executing, to get rid of the leading whitespace. This is "The Wrong Way" of doing it, because this operation is supposed to be done at compile-time. The reason is, there is nothing in this operation that requires run-time information, all information needed for this is known at compile-time.
To do it at compile-time, I wrote a Babel plugin named Dedent Template Literals. Basically it works as follows:
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);
Will print:
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.
Interpolations work without any problems as well. Also if you start a line before the first column after the opening backtick of the template literal, the plugin will throw an error, showing the location of the error. If the following file is at src/httpRFC.js
under your project:
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);
The following error will occur while transpiling:
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'
}
It also works with tabs if you are using tabs (and only tabs) for indentation and using spaces (and only spaces) for alignment.
It can be installed by running npm install --save-dev babel-plugin-dedent-template-literals
and used by putting dedent-template-literals
as the first element of the plugins
array in Babel configuration. Further information can be found on the README.
function trim(segments, ...args) {
const lines = segments
.reduce((acc, segment, i) => acc + segment + (args[i] || ''), '') // get raw string
.trimEnd().split('\n') // Split the raw string into lines
.filter(line => line != "") // remove empty lines
// Find the minimum number of leading spaces across all lines
const minLeadingSpaces = lines.reduce((acc, line) => {
// Find the number of leading spaces for this line
const leadingSpaces = line.match(/^ */)[0].length
// if it has less leading spaces than the previous minimum, set it as the new minimum
return leadingSpaces < acc ? leadingSpaces : acc
}, Infinity)
// Trim lines, join them and return the result
return lines.map(line => line.substring(minLeadingSpaces)).join('\n')
}
Usage:
console.log(trim`
<div>
<p>
Lorem ipsum dolor sit amet.
</p>
</div>
`)
As Šime Vidas states, functions can be used as a tag, and invoked by just placing it in front of the template string.
A number of NPM modules exist to do this, and will cover many edge cases that would be hard to cover yourself. The main two are:
dedent, 4 million weekly downloads, last updated 4 years ago
endent, 2.5 thousand weekly downloads, updated 4 months ago
If you don't want to use a library and don't want to loose all "indentation structure" you can use this function:
function dedent(str) {
const smallestIndent = Math.min(...str
.split('\n')
.filter(line => line.trim())
.map(line => line.match(/^\s*/)[0].length)
);
return str
.split('\n')
.map(line => line.slice(smallestIndent))
.join('\n');
}
The function figures out the smallest indent every line has in common, an then strips this amount of characters from each line.
This converts this:
<head>
<link rel='stylesheet' href='${server[source]}/widget.css'>
</head>
<body>
${widgetContainerText}
<script type='module' src='${server[source]}/widget.js'>
</body>
to this:
<head>
<link rel='stylesheet' href='${server[source]}/widget.css'>
</head>
<body>
${widgetContainerText}
<script type='module' src='${server[source]}/widget.js'>
</body>
A proposal that adds a String.dedent
tag template function is now on Stage 2!
When it reaches Stage 4 and is implemented on most major browsers, you will be able to write:
const a = String.dedent`
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);
which will output:
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
Until then, there is a core-js polyfill that you can use:
const a = String.dedent`
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);
<script src="https://unpkg.com/[email protected]/minified.js"></script>
I would suggest using an Array of string literals and then join the Array into a String.
This suggestion isn't ideal, imho, due to having to create an Array and then a manipulation, but to me it allows readability which is why I think the original poster desires multiline literal with indentation.
Using the original post as an example...
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`;
Using Array + join
var a = [
`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`,
].join(" ")
本文标签: javascriptHow can I remove indentation from multiline stringsStack Overflow
版权声明:本文标题:javascript - How can I remove indentation from multiline strings? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736858268a1955805.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
String.dedent
is currently on Stage 2. I've posted an answer with details on how to use it. – double-beep Commented Sep 2, 2024 at 12:52