How to escape control characters?
Steven Schveighoffer
schveiguy at gmail.com
Tue Aug 23 13:09:01 UTC 2022
On 8/23/22 6:09 AM, Bastiaan Veelo wrote:
> On Thursday, 31 March 2016 at 03:15:49 UTC, cy wrote:
>> This might be a dumb question. How do I format a string so that all
>> the newlines print as \n and all the tabs as \t and such?
>
> The easiest is this:
>
> ```d
> import std.conv;
> string str = `Hello "World"
> line 2`;
> writeln([str].text[2..$-2]); // Hello \"World\"\nline 2
> ```
>
> I know this is an old post, but I felt this trick needed to be shared.
>
> This takes advantage of the fact that `std.format` escapes the
> characters in an array of strings. So we create an array where `str` is
> the only element, and convert that to text. Without the `[2..$-2]`
> slicing the output would be `["Hello \"World\"\nline 2"]`.
>
> A slightly more efficient implementation is
> ```d
> string escape(string s)
> {
> import std.array : appender;
> import std.format : FormatSpec, formatValue;
>
> FormatSpec!char f;
> auto w = appender!string;
> w.reserve(s.length);
> formatValue(w, [s], f);
> return w[][2 .. $ - 2];
> }
> ```
Without allocations. This took me longer than I had hoped it would. It
needs the 1-char buffer to avoid sending the surrounding quotes.
```d
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 => empty, 0x0, empty, but not first
void putter(const(char)[] data) {
if(!data.length) return;
if(buf != 0xff)
{
if(buf)
put(output, buf);
}
else
// skip first "
data = data[1 .. $];
if(!data.length){
buf = 0;
return;
}
put(output, data[0 .. $-1]);
buf = data[$-1];
}
scope x = &putter;
formattedWrite(x, "%(%s%)", str[]);
}
}
```
It would be nice to expose the escaping functionality from format so
this kind of trickery isn't necessary.
-Steve
More information about the Digitalmars-d-learn
mailing list