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