On Tuesday, 23 August 2022 at 23:17:21 UTC, Salih Dincer wrote:

The nice thing here is that you can change the format specifiers as you wish.

Actually, both structures could be combined:

```d
struct EscapedString
{
   string[1] str;
   this(string str) @nogc pure nothrow @safe
   {
     this.str[0] = str;
   }

   import std.format, std.range;
   void toString(scope void delegate(const(char)[]) sink,
                 FormatSpec!char fmt)const
   {
     if(fmt.spec == 'e')
     {
       char buf;
       formattedWrite((const(char)[] data) {
         if(!data.length) return;

         if(buf < 0xff) put(sink, buf);
         else data = data[1 .. $];

         if(data.length) {
           put(sink, data[0 .. $-1]);
           buf = data[$-1];
         } else {
           buf = 0;
           return;
         }
       }, "%(%s%)", str[]);
     } else sink.formattedWrite("%s", str[0]);
   }
} unittest {
  import std.array : appender;
  import std.format;

  auto str = EscapedString();
  auto app = appender!string;

  app.formattedWrite("%e", str);
  assert(app.data.length == 0);

  auto results = [`a\tb`, `a\tba\nb`, `a\tba\nba\rb`,
                  `a\tba\nba\rba b`, `a\tba\nba\rba ba\"b`
                 ];

  foreach(i, char c; [9, 10, 13, 32, 34]) {
    const s = "a" ~ c ~ "b";
    app.formattedWrite("%e", EscapedString(s));
    assert(app.data == results[i],
           format("%s, i = %s", app.data, i));
  }
}
```

SDB@79


Reply via email to