如何​​格式化​​​串,来显示打印​​\n​​​和​​\t​​等?

r"ab\n"
//或
`ab\n`
//或
"abc\\ndef\\tghi"

但如果是​​运行时​​​串,可能必须用​​std.regex.replaceAll​​​等来​​手动​​​转义字符.或用​​管道​​手动替换:

string myString = ...;
string escapedStr = myString
.chunks(1)
.map!(c => (c == "\n") ? "\\n" :
(c == "\r") ? "\\r" :
(c == "\t") ? "\\t" :
c)
.joiner
.array;

这样:

string a = r"ab\n";
writeln(escape(a)); // => ab\n
//我这样
string escapedStr = myString
.replace("\n",`\n`)
.replace("\r",`\r`)
.replace("\t",`\t`);

或这样:

auto escapedStr = appender!string;
for(c;myString) {
switch(c) {
case '\n':
escapedStr.put("\\n");
case '\r':
escapedStr.put("\\r");
...
default:
escapedStr.put(c);
}
}

​最简单​​的是这样:

import std.conv;
string str = `Hello "World"
line 2`;
writeln([str].text[2..$-2]); // Hello \"World\"\nline 2

这利用了​​std.format​​​转义了​​串数组​​​中字符.我们创建​​str​​​为​​唯一元素​​​的数组,并转换它为文本.如果没有​​[2..$-2]​​​切片,输出将是​​["Hello\"World\"\nline2"]​​​.
一个稍微更有效的实现是:

string escape(string s)
{
import std.array :;
import std.format :, formatValue;

FormatSpec!char f;
auto w = appender!string;
w.reserve(s.length);
formatValue(w, [s], f);
return w[][2 .. $ - 2];
}
//反函数

string unescape(string s)
{
import std.format :, unformatValue;

FormatSpec!char f;
string str = `["` ~ s ~ `"]`;
return unformatValue!(string[])(str, f)[0];
}

​escape()​​​和​​unescape()​​​应为​​std.format​​​部分,然后,可直接用​​std.format.internal.write.formatElement​​来避免转换至数组.

没有分配.如下需要​​1符​​​缓冲区来避免发送​​包围​​的引号.

struct EscapedString
{
string[1] str;
this(string str) @nogc pure nothrow @safe { this.str[0] = str; }
void toString(Out)(auto ref Out output)
{
import std.format;
import std.range;
char buf; // 0xff => 空的, 0x0, 空的,但不是第1个
void putter(const(char)[] data) {
if(!data.length) return;
if(buf != 0xff)
{
if(buf)
put(output, buf);
}
else
// 跳过第1个 "
data = data[1 .. $];
if(!data.length){
buf = 0;
return;
}
put(output, data[0 .. $-1]);
buf = data[$-1];
}
scope x = &putter;
formattedWrite(x, "%(%s%)", str[]);
}
}

从​​格式​​​中公开​​转义功能​​​会很好,就不需要这种技巧了.
自定义包装串.

struct String {
string str;
alias str this;
import std.format, std.string;
void toString(scope void delegate(const(char)[]) sink,FormatSpec!char fmt)const
{
auto arr = str.lineSplitter;
if(fmt.spec == 'n') {
sink.formattedWrite("%-(%s\\n%)", arr);
} else sink.formattedWrite("%s", str);
}
} unittest {
import std.stdio;
auto str = `这是
`;
String Str; // 简单构造器
Str = str; // 直接赋值

Str.writefln!"%n"; // "这是\n串"
Str.writefln!"%s"; /*
这是

*/
}