IEscaper
IEscaper is an interface for string escapers.
/// <summary>Escaper</summary>
public interface IEscaper
{
/// <summary>Estimate number of chars required to escaped version of <paramref name="unescapedInput"/>.</summary>
/// <returns>Number of chars in escaped version of <paramref name="unescapedInput"/>. -1 if could not estimate</returns>
int EstimateEscapedLength(ReadOnlySpan<char> unescapedInput);
/// <summary>Estimate number of chars required in unescaped version of <paramref name="escapedInput"/>.</summary>
/// <returns>Number of chars in unescaped version of <paramref name="escapedInput"/>. -1 if could not estimate.</returns>
int EstimateUnescapedLength(ReadOnlySpan<char> escapedInput);
/// <summary>Escape <paramref name="unescapedInput"/> into <paramref name="escapedOutput"/>.</summary>
/// <returns>Number of characters written to <paramref name="escapedOutput"/>. -1 if escape failed.</returns>
int Escape(ReadOnlySpan<char> unescapedInput, Span<char> escapedOutput);
/// <summary>Unescape <paramref name="escapedInput"/> into <paramref name="unescapedOutput"/>.</summary>
/// <returns>Number of characters written to <paramref name="unescapedOutput"/>. -1 if unescape failed.</returns>
/// <remarks>If escaper uses separator, then this method regardless unescapes the whole input and proceed through all separators.</remarks>
int Unescape(ReadOnlySpan<char> escapedInput, Span<char> unescapedOutput);
}
IEscaperSplitter is an extension interface for split capable escapers.
/// <summary>Unescapes and escapes with separator char/string.</summary>
public interface IEscaperSplitter : IEscaper
{
/// <summary>Indicates whether escaper uses separator and can split parts</summary>
bool CanSplit { get; }
/// <summary>Separator string</summary>
string? Separator { get; }
/// <summary>Seeks until end of <paramref name="escapedInput"/> or until start of <see cref="Separator"/> sequence.</summary>
/// <returns>Returns count of escaped and unescaped characters that scan forwarded</returns>
(int escapedLength, int unescapedLength) SeekSeparator(ReadOnlySpan<char> escapedInput);
/// <summary>Seeks until end of <paramref name="escapedInput"/> or until unescaped character that should be escaped occurs.</summary>
/// <returns>Returns count of escaped and unescaped characters that scan forwarded</returns>
(int escapedLength, int unescapedLength) SeekUnescaped(ReadOnlySpan<char> escapedInput);
}
Escaper
Escaper is generic escaper implementation.
// Create escaper
IEscaper escaper = new Escaper(
escapeChar: '\\',
separatorChar: ',',
escapeMap: Escaper.ControlCharEscapeMap,
unescapeMap: Escaper.ControlCharUnescapeMap
);
Escaper.Create(escapeChar, separatorChar, toEscapeChars) gives easier construction.
// Create escaper
IEscaper escaper = Escaper.Create(
escapeChar: '\\',
separatorChar: ',',
toEscapeChars: "()".ToCharArray()
);
// Escape
WriteLine(escaper.Escape(@"a(),b()")); // @"a\(\),b\(\)"
// Unescape
WriteLine(escaper.Unescape(@"a\(\),b\(\)")); // @"a(),b()"
.UnescapeSplit(readonlySpan) unescapes a span and splits with associated separator.
List<string> splits = escaper.UnescapeSplit(@"a\(\),b\(\)");
.EscapeJoin(parts) escapes and joins parts.
string join = escaper.EscapeJoin(splits);
.TryUnescapeSplit(readonlySpan, ref parts) tries to unescape a span and splits with separator.
// Reserver 4 slots from stack
StructList4<string> list = new StructList4<string>();
// Unescape and split ','
if (escaper.TryUnescapeSplit(@"a\(\),b\(\)", ref list))
foreach (var part in list) WriteLine(part); // "a()", "b()"
.TryEscapeJoin(parts, out joined) tries to escape and joins parts.
// Join with ',' and escape
if (escaper.TryEscapeJoin(list, out string? joined))
WriteLine(joined); // @"a\(\),b\(\)"
Escaper.Backslash escapes backslashes.
IEscaper escaper = Escaper.Backslash;
WriteLine(escaper.Escape(@"Value\Value\Value")); // @"Value\\Value\\Value"
WriteLine(escaper.Unescape(@"Value\\Value\\Value")); // @"Value\Value\Value"
Escaper.Dot escapes dots and uses backslash as escape character.
IEscaper escaper = Escaper.Dot;
WriteLine(escaper.Escape(@"Value.Value.Value")); // @"Value\.Value\.Value"
WriteLine(escaper.Unescape(@"Value\.Value\.Value")); // @"Value.Value.Value"
WriteLine(escaper.Escape(@"Value\.Value\.Value")); // @"Value\\\.Value\\\.Value"
WriteLine(escaper.Unescape(@"Value\\\.Value\\\.Value")); // @"Value\.Value\.Value"
Escaper.Comma escapes commas and uses backslash as escape character.
string[] args = { "Arg,0", "Arg1", "Arg2" };
string join = Escaper.Comma.EscapeJoin(args);
WriteLine(join); // "Arg\,0,Arg1,Arg2"
Escaper.Semicolon escapes and parses csv lines.
string[] args = { "Arg,0", "Arg1", "Arg2" };
string csvLine = Escaper.Semicolon.EscapeJoin(args);
WriteLine(csvLine); // "Arg,0;Arg1;Arg2"
Escaper.Colon escapes and parses with ':'.
string[] args = { "Arg,0", "Arg1", "Arg2" };
string line = Escaper.Colon.EscapeJoin(args);
WriteLine(line); // "Arg,0:Arg1:Arg2"
Escaper.Quotes escapes quotes " with backslash "\"".
IEscaper escaper = Escaper.Quotes;
WriteLine(escaper.Escape(@"""Hello world""")); // "\"Hello world\""
WriteLine(escaper.Unescape("\"Hello world\"")); // @"""Hello world"""
Escaper.Brace escapes "{" as "{{" and "}" as "}}". Does not escape control characters.
IEscaper escaper = Escaper.Brace;
WriteLine(escaper.Escape("Hello {0}")); // "Hello {{0}}"
WriteLine(escaper.Unescape("Hello {{0}}")); // "Hello {0}"
Escaper.Create() constructed escaper adds automatically the following control characters: \0\a\b\v\f\n\r to be escaped as respective strings "\\0\\a\\b\\v\\f\\n\\r". Tabulator character '\t' is not escaped, but is unescaped from "\\t".
IEscaper escaper = Escaper.Dot;
WriteLine(escaper.Escape("\0\a\b\v\f\n\r")); // @"\0\a\b\v\f\n\r"
WriteLine(escaper.Unescape(@"\0\a\b\v\f\n\r\t")); // "\0\a\b\v\f\n\r\t"
Escape is based on the configured escape char.
IEscaper escaper = Escaper.Create('-', '-');
WriteLine(escaper.Escape("\0\a\b\v\f\n\r")); // @"-0-a-b-v-f-n-r"
WriteLine(escaper.Unescape("-0-a-b-v-f-n-r-t")); // "\0\a\b\v\f\n\r\t"
Tabulator escaping can be explicitly added.
IEscaper escaper = Escaper.Create('-', '-', '\t');
WriteLine(escaper.Escape("\0\a\b\v\f\n\r\t")); // @"-0-a-b-v-f-n-r-t"
WriteLine(escaper.Unescape("-0-a-b-v-f-n-r-t")); // "\0\a\b\v\f\n\r\t"
Full Example
Full example
using System.Collections.Generic;
using Avalanche.Utilities;
using static System.Console;
public class escaper
{
public static void Run()
{
{
// <00>
// Create escaper
IEscaper escaper = new Escaper(
escapeChar: '\\',
separatorChar: ',',
escapeMap: Escaper.ControlCharEscapeMap,
unescapeMap: Escaper.ControlCharUnescapeMap
);
// </00>
}
{
// <01>
// Create escaper
IEscaper escaper = Escaper.Create(
escapeChar: '\\',
separatorChar: ',',
toEscapeChars: "()".ToCharArray()
);
// Escape
WriteLine(escaper.Escape(@"a(),b()")); // @"a\(\),b\(\)"
// Unescape
WriteLine(escaper.Unescape(@"a\(\),b\(\)")); // @"a(),b()"
// </01>
// <02>
List<string> splits = escaper.UnescapeSplit(@"a\(\),b\(\)");
// </02>
// <03>
string join = escaper.EscapeJoin(splits);
// </03>
// <04>
// Reserver 4 slots from stack
StructList4<string> list = new StructList4<string>();
// Unescape and split ','
if (escaper.TryUnescapeSplit(@"a\(\),b\(\)", ref list))
foreach (var part in list) WriteLine(part); // "a()", "b()"
// </04>
// <05>
// Join with ',' and escape
if (escaper.TryEscapeJoin(list, out string? joined))
WriteLine(joined); // @"a\(\),b\(\)"
// </05>
}
{
// <11>
IEscaper escaper = Escaper.Backslash;
WriteLine(escaper.Escape(@"Value\Value\Value")); // @"Value\\Value\\Value"
WriteLine(escaper.Unescape(@"Value\\Value\\Value")); // @"Value\Value\Value"
// </11>
}
{
// <12>
IEscaper escaper = Escaper.Dot;
WriteLine(escaper.Escape(@"Value.Value.Value")); // @"Value\.Value\.Value"
WriteLine(escaper.Unescape(@"Value\.Value\.Value")); // @"Value.Value.Value"
WriteLine(escaper.Escape(@"Value\.Value\.Value")); // @"Value\\\.Value\\\.Value"
WriteLine(escaper.Unescape(@"Value\\\.Value\\\.Value")); // @"Value\.Value\.Value"
// </12>
}
{
// <12B>
string[] args = { "Arg,0", "Arg1", "Arg2" };
string join = Escaper.Comma.EscapeJoin(args);
WriteLine(join); // "Arg\,0,Arg1,Arg2"
// </12B>
}
{
// <12C>
string[] args = { "Arg,0", "Arg1", "Arg2" };
string csvLine = Escaper.Semicolon.EscapeJoin(args);
WriteLine(csvLine); // "Arg,0;Arg1;Arg2"
// </12C>
}
{
// <12D>
string[] args = { "Arg,0", "Arg1", "Arg2" };
string line = Escaper.Colon.EscapeJoin(args);
WriteLine(line); // "Arg,0:Arg1:Arg2"
// </12D>
}
{
// <13>
IEscaper escaper = Escaper.Quotes;
WriteLine(escaper.Escape(@"""Hello world""")); // "\"Hello world\""
WriteLine(escaper.Unescape("\"Hello world\"")); // @"""Hello world"""
// </13>
}
{
// <14>
IEscaper escaper = Escaper.Dot;
WriteLine(escaper.Escape("\0\a\b\v\f\n\r")); // @"\0\a\b\v\f\n\r"
WriteLine(escaper.Unescape(@"\0\a\b\v\f\n\r\t")); // "\0\a\b\v\f\n\r\t"
// </14>
}
{
// <15>
IEscaper escaper = Escaper.Create('-', '-');
WriteLine(escaper.Escape("\0\a\b\v\f\n\r")); // @"-0-a-b-v-f-n-r"
WriteLine(escaper.Unescape("-0-a-b-v-f-n-r-t")); // "\0\a\b\v\f\n\r\t"
// </15>
}
{
// <16>
IEscaper escaper = Escaper.Create('-', '-', '\t');
WriteLine(escaper.Escape("\0\a\b\v\f\n\r\t")); // @"-0-a-b-v-f-n-r-t"
WriteLine(escaper.Unescape("-0-a-b-v-f-n-r-t")); // "\0\a\b\v\f\n\r\t"
// </16>
}
{
// <19>
IEscaper escaper = Escaper.Brace;
WriteLine(escaper.Escape("Hello {0}")); // "Hello {{0}}"
WriteLine(escaper.Unescape("Hello {{0}}")); // "Hello {0}"
// </19>
}
}
}