digitalmars.D.learn - How to escape control characters?
- cy (2/2) Mar 30 2016 This might be a dumb question. How do I format a string so that
- Seb (3/5) Mar 30 2016 http://dlang.org/spec/lex.html#WysiwygString
- H. S. Teoh via Digitalmars-d-learn (18/25) Mar 30 2016 Or the verbose way:
- cy (27/37) Mar 30 2016 What I did was
- cy (4/6) Mar 30 2016 Yes I know. But I mean like,
- Bastiaan Veelo (43/45) Aug 23 2022 The easiest is this:
- Steven Schveighoffer (38/72) Aug 23 2022 Without allocations. This took me longer than I had hoped it would. It
- Salih Dincer (38/41) Aug 23 2022 Surely what Steve does is better. But for some reason I like
- Salih Dincer (50/52) Aug 24 2022 Actually, both structures could be combined:
- Gerardo Cahn (5/16) Sep 19 Thanks to all. I am using the code listed here. I can't but
- kdevel (19/20) Sep 20 It should be left to posterity that the code presented in this
- Salih Dincer (58/75) Sep 22 This must be a metaphor, from the past...
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?
Mar 30 2016
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?http://dlang.org/spec/lex.html#WysiwygString r"ab\n" or `ab\n`
Mar 30 2016
On Thu, Mar 31, 2016 at 03:23:52AM +0000, Seb via Digitalmars-d-learn wrote:On Thursday, 31 March 2016 at 03:15:49 UTC, cy wrote:Or the verbose way: "abc\\ndef\\tghi" But if the string is only known at runtime, you'd probably have to use std.regex.replaceAll or something like that to manually escape characters. Or implement manual substitution with a pipeline: string myString = ...; string escapedStr = myString .chunks(1) .map!(c => (c == "\n") ? "\\n" : (c == "\r") ? "\\r" : (c == "\t") ? "\\t" : c) .joiner .array; T -- Береги платье снову, а здоровье смолоду.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?http://dlang.org/spec/lex.html#WysiwygString r"ab\n" or `ab\n`
Mar 30 2016
Oh, cool. On Thursday, 31 March 2016 at 03:29:19 UTC, H. S. Teoh wrote:Or implement manual substitution with a pipeline: string myString = ...; string escapedStr = myString .chunks(1) .map!(c => (c == "\n") ? "\\n" : (c == "\r") ? "\\r" : (c == "\t") ? "\\t" : c) .joiner .array;What I did was string escapedStr = myString .replace("\n",`\n`) .replace("\r",`\r`) .replace("\t",`\t`); That makes like 3 copies of the string I guess, but whatever. I'm not sure how efficient a general chunking filter would be on 1-byte chunks, and I certainly don't want to be creating a zillion unescaped 1-byte strings, so if I cared I'd probably do something like this: auto escapedStr = appender!string; for(c;myString) { switch(c) { case '\n': escapedStr.put("\\n"); case '\r': escapedStr.put("\\r"); ... default: escapedStr.put(c); } } It'd have to be long and boring to get all the control characters though, and possibly unicode ones too, or do "\xNN" style byte escapes. So I was hoping something standard already existed.
Mar 30 2016
On Thursday, 31 March 2016 at 03:23:52 UTC, Seb wrote:http://dlang.org/spec/lex.html#WysiwygString r"ab\n" or `ab\n`Yes I know. But I mean like, string a = r"ab\n"; writeln(escape(a)); // => ab\n
Mar 30 2016
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]; } ``` And the inverse: ```d string unescape(string s) { import std.format : FormatSpec, unformatValue; FormatSpec!char f; string str = `["` ~ s ~ `"]`; return unformatValue!(string[])(str, f)[0]; } ``` Perhaps `escape()` and `unescape()` should be part of `std.format` so that they can be refactored to use `std.format.internal.write.formatElement` directly, eliminating the conversion to array. -- Bastiaan.
Aug 23 2022
On 8/23/22 6:09 AM, Bastiaan Veelo wrote:On Thursday, 31 March 2016 at 03:15:49 UTC, cy wrote: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. -SteveThis 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]; } ```
Aug 23 2022
On Tuesday, 23 August 2022 at 13:09:01 UTC, Steven Schveighoffer wrote:Without allocations. This took me longer than I had hoped it would. It needs the 1-char buffer to avoid sending the surrounding quotes.Surely what Steve does is better. But for some reason I like simple and useful things. I sometimes use custom string wrapping. Maybe it will be useful for you, for example: ```d 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 = `this is a string`; String Str; // simple constructor Str = str; // direct assign Str.writefln!"%n"; // "this\n is a\n string" Str.writefln!"%s"; /* this is a string */ } ``` The nice thing here is that you can change the format specifiers as you wish. Thank you all... SDB 79
Aug 23 2022
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
Aug 24 2022
On Wednesday, 24 August 2022 at 08:12:33 UTC, Salih Dincer wrote:On Tuesday, 23 August 2022 at 23:17:21 UTC, Salih Dincer wrote:...Actually, both structures could be combined: ```d struct EscapedString { string[1] str; this(string str) nogc pure nothrow safe { ...(rest clipped) ``` SDB 79Thanks to all. I am using the code listed here. I can't but feel like Salieri with Mozart: I know enough D to appreciate this thread, but not enough to create this on my own...
Sep 19
On Thursday, 19 September 2024 at 14:30:08 UTC, Gerardo Cahn wrote:I am using the code listed here.It should be left to posterity that the code presented in this thread cannot properly escape ``` "A\xfeZ" ``` ``` BV's escape: cast(char) 0x41, cast(char) 0xFE, cast(char) 0x5A steve's: cast(char) 0x41, cast(char) 0xFE, cast(char) 0x5A ``` nor ("and possibly unicode ones too,", cy March 31, 2016) ``` "A\u00fcZ" ``` ``` BV's escape: AüZ steve's: AüZ ```
Sep 20
On Thursday, 19 September 2024 at 14:30:08 UTC, Gerardo Cahn wrote:On Wednesday, 24 August 2022 at 08:12:33 UTC, Salih Dincer wrote:This must be a metaphor, from the past... I would like to thank you for saying "hello" to the silence. Thanks to you, I have just developed the missing parts of the code. I am sure that if the silent majority criticized such codes, the field would be beautiful. I hadn't thought about UTF codes before, they seem to work. What do you think? ```d import std.stdio; void main() { enum str = r"\tHello\xfeD\r\nProgramming\0\nWorld!\b\f"; auto u = str.unescaped(); auto e = u.escaped(); assert(e == str); u.unescaped.writeln; } auto escaped(string str) { import std.algorithm : map; import std.conv : to, toChars; import std.string : format; return str.map!(chr => () { auto code = chr.to!ulong; if (code >= 0x7f) { return code.toChars!(16, char) .format!"\\x%-(%c%)"; } switch (code) { case '\0': return `\0`; case '\b': return `\b`; case '\f': return `\f`; case '\t': return `\t`; case '\n': return `\n`; case '\r': return `\r`; case '"': return `\"`; case '\'': return `\'`; case '\\': return `\\`; //case ' ': return `\s`; default: return chr.to!string; } }()).format!"%-(%s%)"; } string unescaped(string str) { import std.format : fs = FormatSpec; import std.format : uv = unformatValue; fs!char f; auto s = `["` ~ str ~ `"]`; return uv!(string[])(s, f)[0]; } ``` SDB 79On Tuesday, 23 August 2022 at 23:17:21 UTC, Salih Dincer wrote:...Actually, both structures could be combined: ```d struct EscapedString { string[1] str; this(string str) nogc pure nothrow safe { ...(rest clipped) ```Thanks to all. I am using the code listed here. I can't but feel like Salieri with Mozart: I know enough D to appreciate this thread, but not enough to create this on my own...
Sep 22