www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to escape control characters?

reply cy <dlang verge.info.tm> writes:
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
next sibling parent reply Seb <seb wilzba.ch> writes:
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
next sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
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:
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`
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 -- Береги платье снову, а здоровье смолоду.
Mar 30 2016
parent cy <dlang verge.info.tm> writes:
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
prev sibling parent cy <dlang verge.info.tm> writes:
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
prev sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
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
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 23 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
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
parent Salih Dincer <salihdb hotmail.com> writes:
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