public static int UnescapeChar(string s, ref int i) { UString s2 = new UString(s, i); EscapeC _ = 0; int result = UnescapeChar(ref s2, ref _); i = s2.InternalStart; return(result); }
/// <summary>Escapes characters in a string using C style.</summary> /// <param name="flags">Specifies which characters should be escaped.</param> /// <param name="quoteType">Specifies a character that should always be /// escaped (typically one of <c>' " `</c>)</param> public static string EscapeCStyle(UString s, EscapeC flags, char quoteType) { StringBuilder s2 = new StringBuilder(s.Length+1); bool usedEscapes = false, fail; for (;;) { int c = s.PopFirst(out fail); if (fail) break; usedEscapes |= EscapeCStyle(c, s2, flags, quoteType); } if (!usedEscapes && s.InternalString.Length == s.Length) return s.InternalString; return s2.ToString(); }
static void EscapeU(char c, StringBuilder @out, EscapeC flags) { if (c <= 255 && (flags & EscapeC.BackslashX) != 0) { @out.Append(@"\x"); } else { @out.Append(@"\u"); @out.Append(HexDigitChar((c >> 12) & 0xF)); @out.Append(HexDigitChar((c >> 8) & 0xF)); } @out.Append(HexDigitChar((c >> 4) & 0xF)); @out.Append(HexDigitChar(c & 0xF)); }
public static string EscapeCStyle(UString s, EscapeC flags, char quoteType) { StringBuilder s2 = new StringBuilder(s.Length + 1); bool any = false; for (int i = 0; i < s.Length; i++) { char c = s[i]; any |= EscapeCStyle(c, s2, flags, quoteType); } if (!any && s.InternalString.Length == s.Length) { return(s.InternalString); } return(s2.ToString()); }
/// <summary>Unescapes a string that uses C-style escape sequences, e.g. /// "\\\n\\\r" becomes "\n\r".</summary> /// <param name="encountered">Returns information about whether escape /// sequences were encountered, and which categories.</param> /// <param name="removeUnnecessaryBackslashes">Causes the backslash before /// an unrecognized escape sequence to be removed, e.g. "\z" => "z".</param> /// <remarks>See <see cref="UnescapeChar(ref UString, ref EscapeC)"/> for details.</remarks> public static StringBuilder UnescapeCStyle(UString s, out EscapeC encountered, bool removeUnnecessaryBackslashes = false) { encountered = 0; StringBuilder @out = new StringBuilder(s.Length); while (s.Length > 0) { EscapeC encounteredHere = 0; int c = UnescapeChar(ref s, ref encounteredHere); encountered |= encounteredHere; if (removeUnnecessaryBackslashes && (encounteredHere & EscapeC.Unrecognized) != 0) { Debug.Assert(c == '\\'); continue; } @out.AppendCodePoint(c); } return @out; }
/// <summary>Unescapes a string that uses C-style escape sequences, e.g. "\n\r" becomes @"\n\r".</summary> /// <param name="encountered">Returns information about whether escape /// sequences were encountered, and which categories.</param> /// <param name="removeUnnecessaryBackslashes">Causes the backslash before /// an unrecognized escape sequence to be removed, e.g. "\z" => "z".</param> public static string UnescapeCStyle(string s, int index, int length, out EscapeC encountered, bool removeUnnecessaryBackslashes = false) { encountered = 0; StringBuilder s2 = new StringBuilder(length); for (int i = index; i < index + length;) { int oldi = i; char c = UnescapeChar(s, ref i, ref encountered); if (removeUnnecessaryBackslashes && c == '\\' && i == oldi + 1) { continue; } s2.Append(c); } return(s2.ToString()); }
static void EscapeU(int c, StringBuilder @out, EscapeC flags) { if (c <= 255 && (flags & EscapeC.BackslashX) != 0) @out.Append(@"\x"); else { @out.Append(@"\u"); if (c > 0xFFFF || (flags & EscapeC.HasLongEscape) != 0) { Debug.Assert(c <= 0x10FFFF); @out.Append(HexDigitChar((c >> 20) & 0xF)); @out.Append(HexDigitChar((c >> 16) & 0xF)); } @out.Append(HexDigitChar((c >> 12) & 0xF)); @out.Append(HexDigitChar((c >> 8) & 0xF)); } @out.Append(HexDigitChar((c >> 4) & 0xF)); @out.Append(HexDigitChar(c & 0xF)); }
/// <summary>Unescapes a string that uses C-style escape sequences, e.g. /// "\\\n\\\r" becomes "\n\r".</summary> /// <param name="encountered">Returns information about whether escape /// sequences were encountered, and which categories.</param> /// <param name="removeUnnecessaryBackslashes">Causes the backslash before /// an unrecognized escape sequence to be removed, e.g. "\z" => "z".</param> /// <remarks>See <see cref="UnescapeChar(ref UString, ref EscapeC)"/> for details.</remarks> public static StringBuilder UnescapeCStyle(UString s, out EscapeC encountered, bool removeUnnecessaryBackslashes = false) { encountered = 0; StringBuilder @out = new StringBuilder(s.Length); while (s.Length > 0) { EscapeC encounteredHere = 0; int c = UnescapeChar(ref s, ref encounteredHere); encountered |= encounteredHere; if (removeUnnecessaryBackslashes && (encounteredHere & EscapeC.Unrecognized) != 0) { Debug.Assert(c == '\\'); continue; } @out.AppendCodePoint(c); } return(@out); }
/// <summary>Escapes characters in a string using C style.</summary> /// <param name="flags">Specifies which characters should be escaped.</param> /// <param name="quoteType">Specifies a character that should always be /// escaped (typically one of <c>' " `</c>)</param> public static string EscapeCStyle(UString s, EscapeC flags, char quoteType) { StringBuilder s2 = new StringBuilder(s.Length + 1); bool usedEscapes = false, fail; for (;;) { int c = s.PopFirst(out fail); if (fail) { break; } usedEscapes |= EscapeCStyle(c, s2, flags, quoteType); } if (!usedEscapes && s.InternalString.Length == s.Length) { return(s.InternalString); } return(s2.ToString()); }
static void EscapeU(int c, StringBuilder @out, EscapeC flags) { if (c <= 255 && (flags & EscapeC.BackslashX) != 0) { @out.Append(@"\x"); } else { @out.Append(@"\u"); if (c > 0xFFFF || (flags & EscapeC.HasLongEscape) != 0) { Debug.Assert(c <= 0x10FFFF); @out.Append(HexDigitChar((c >> 20) & 0xF)); @out.Append(HexDigitChar((c >> 16) & 0xF)); } @out.Append(HexDigitChar((c >> 12) & 0xF)); @out.Append(HexDigitChar((c >> 8) & 0xF)); } @out.Append(HexDigitChar((c >> 4) & 0xF)); @out.Append(HexDigitChar(c & 0xF)); }
/// <summary>Writes a character <c>c</c> to a StringBuilder, either as a normal /// character or as a C-style escape sequence.</summary> /// <param name="flags">Specifies which characters should be escaped.</param> /// <param name="quoteType">Specifies a character that should always be /// escaped (typically one of <c>' " `</c>)</param> /// <returns>true if an escape sequence was emitted, false if not.</returns> /// <remarks><see cref="EscapeC.HasLongEscape"/> can be used to force a 6-digit /// unicode escape; this may be needed if the next character after this one /// is a digit.</remarks> public static bool EscapeCStyle(int c, StringBuilder @out, EscapeC flags = EscapeC.Default, char quoteType = '\0') { for (;;) { if (c >= 128) { if ((flags & EscapeC.NonAscii) != 0) { EscapeU(c, @out, flags); } else if (c >= 0xDC00) { if ((flags & EscapeC.UnicodeNonCharacters) != 0 && ( c >= 0xFDD0 && c <= 0xFDEF || // 0xFDD0...0xFDEF (c & 0xFFFE) == 0xFFFE) || // 0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, etc. (c & 0xFC00) == 0xDC00) // 0xDC00...0xDCFF { EscapeU(c, @out, flags); } else if ((flags & EscapeC.UnicodePrivateUse) != 0 && ( c >= 0xE000 && c <= 0xF8FF || c >= 0xF0000 && c <= 0xFFFFD || c >= 0x100000 && c <= 0x10FFFD)) { EscapeU(c, @out, flags); } else { break; } } else { break; } } else if (c < 32) { if (c == '\n') { @out.Append(@"\n"); } else if (c == '\r') { @out.Append(@"\r"); } else if (c == '\0') { @out.Append(@"\0"); } else { if ((flags & EscapeC.ABFV) != 0) { if (c == '\a') // 7 (alert) { @out.Append(@"\a"); return(true); } if (c == '\b') // 8 (backspace) { @out.Append(@"\b"); return(true); } if (c == '\f') // 12 (form feed) { @out.Append(@"\f"); return(true); } if (c == '\v') // 11 (vertical tab) { @out.Append(@"\v"); return(true); } } if ((flags & EscapeC.Control) != 0) { if (c == '\t') { @out.Append(@"\t"); } else { EscapeU(c, @out, flags); } } else { @out.Append(c); } } } else if (c == '\"' && (flags & EscapeC.DoubleQuotes) != 0) { @out.Append("\\\""); } else if (c == '\'' && (flags & EscapeC.SingleQuotes) != 0) { @out.Append("\\'"); } else if (c == '\\') { @out.Append(@"\\"); } else { break; } return(true); } if (c == quoteType) { @out.Append('\\'); @out.Append((char)c); return(true); } else { @out.AppendCodePoint(c); } return(false); }
/// <summary>Escapes characters in a string using C style, e.g. the string /// <c>"Foo\"\n"</c> maps to <c>"Foo\\\"\\\n"</c> by default.</summary> public static string EscapeCStyle(UString s, EscapeC flags = EscapeC.Default) { return(EscapeCStyle(s, flags, '\0')); }
/// <summary>Parses a normal or triple-quoted string whose starting quotes /// have been stripped out. If triple-quote parsing was requested, stops /// parsing at three quote marks; otherwise, stops parsing at a single /// end-quote or newline.</summary> /// <returns>true if parsing stopped at one or three quote marks, or false /// if parsing stopped at the end of the input string or at a newline (in /// a string that is not triple-quoted).</returns> /// <remarks>This method recognizes LES and EC#-style string syntax.</remarks> public static bool UnescapeString(ref UString sourceText, char quoteType, bool isTripleQuoted, Action <int, string> onError, StringBuilder sb, UString indentation = default(UString), bool allowExtraIndent = false) { Debug.Assert(quoteType == '"' || quoteType == '\'' || quoteType == '`'); bool fail; for (; ;) { if (sourceText.IsEmpty) { return(false); } int i0 = sourceText.InternalStart; if (!isTripleQuoted) { EscapeC category = 0; int c = ParseHelpers.UnescapeChar(ref sourceText, ref category); if ((c == quoteType || c == '\n') && sourceText.InternalStart == i0 + 1) { return(c == quoteType); // end of string } if ((category & EscapeC.Unrecognized) != 0) { // This backslash was ignored by UnescapeChar onError(i0, @"Unrecognized escape sequence '\{0}' in string".Localized(PrintHelpers.EscapeCStyle(sourceText[0, ' '].ToString(), EscapeC.Control))); } else if ((category & EscapeC.HasInvalid6DigitEscape) != 0) { onError(i0, @"Invalid 6-digit \u code treated as 5 digits".Localized()); } sb.AppendCodePoint(c); if ((category & EscapeC.BackslashX) != 0 && c >= 0x80) { DetectUtf8(sb); } else if (c.IsInRange(0xDC00, 0xDFFF)) { RecodeSurrogate(sb); } } else { // Inside triple-quoted string int c; if (sourceText[2, '\0'] == '/') { // Detect escape sequence c = ParseHelpers.UnescapeChar(ref sourceText); if (sourceText.InternalStart > i0 + 1) { G.Verify(sourceText.PopFirst(out fail) == '/'); } } else { c = sourceText.PopFirst(out fail); if (fail) { return(false); } if (c == quoteType) { if (sourceText[0, '\0'] == quoteType && sourceText[1, '\0'] == quoteType) { sourceText = sourceText.Substring(2); // end of string return(true); } } if (c == '\r' || c == '\n') { // To ensure platform independency of source code, CR and // CR-LF become LF. if (c == '\r') { c = '\n'; var copy = sourceText.Clone(); if (sourceText.PopFirst(out fail) != '\n') { sourceText = copy; } } // Inside a triple-quoted string, the indentation following a newline // is ignored, as long as it matches the indentation of the first line. UString src = sourceText, ind = indentation; int sp; while ((sp = src.PopFirst(out fail)) == ind.PopFirst(out fail) && !fail) { sourceText = src; } if (allowExtraIndent && fail) { // Allow an additional one tab or three spaces when initial indent matches if (sp == '\t') { sourceText = src; } else if (sp == ' ') { sourceText = src; if (src.PopFirst(out fail) == ' ') { sourceText = src; } if (src.PopFirst(out fail) == ' ') { sourceText = src; } } } } } sb.AppendCodePoint(c); } } }
public static char UnescapeChar(string s, ref int i) { EscapeC _ = 0; return(UnescapeChar(s, ref i, ref _)); }
/// <summary>Unescapes a single character of a string. Returns the /// first character if it is not a backslash, or <c>\</c> if it is a /// backslash but no escape sequence could be discerned.</summary> /// <param name="s">Slice of a string to be unescaped. When using a /// <c>ref UString</c> overload of this method, <c>s</c> will be shorter upon /// returning from this method, as the parsed character(s) are clipped /// from the beginning (<c>s.InternalStart</c> is incremented by one /// normally and more than one in case of an escape sequence.)</param> /// <param name="encountered">Bits of this parameter are set according /// to which escape sequence is encountered, if any.</param> /// <remarks> /// This function also decodes (non-escaped) surrogate pairs. /// <para/> /// Code points with 5 or 6 digits such as \u1F4A9 are supported. /// \x escapes must be two digits and set the EscapeC.BackslashX flag. /// \u escapes must be 4 to 6 digits. If a \u escape has more than 4 /// digits, the EscapeC.HasLongEscapes flag is set. Invalid 6-digit /// escapes like \u123456 are "made valid" by being treated as 5 digits /// (the largest valid escape is <c>\u10FFFF</c>.) /// <para/> /// Supported escapes: <c>\u \x \\ \n \r \0 \' \" \` \t \a \b \f \v</c> /// </remarks> /// <example> /// EscapeC e = 0; /// UString str = @"\nfoo"; /// char c = UnescapeChar(ref str, ref e); /// Contract.Assert(str == "foo"); /// Contract.Assert(e == EscapeC.HasEscapes); /// </example> public static int UnescapeChar(ref UString s, ref EscapeC encountered) { bool fail; int c = s.PopFirst(out fail); if (c != '\\' || s.Length <= 0) return c; encountered |= EscapeC.HasEscapes; int code; // hex code after \u or \x UString slice, original = s; switch (s.PopFirst(out fail)) { case 'u': slice = s.Left(6); if (TryParseHex(ref slice, out code) >= 4) { if (code <= 0x10FFFF) { s = s.Substring(slice.InternalStart - s.InternalStart); } else { Debug.Assert(slice.Length == 0); // It appears to be 6 digits but only the first 5 can // be treated as part of the escape sequence. s = s.Substring(5); code >>= 4; encountered |= EscapeC.HasInvalid6DigitEscape; } if (slice.InternalStart > s.InternalStart + 4) encountered |= EscapeC.HasLongEscape; if (code < 32) encountered |= EscapeC.Control; else if (code > 127) encountered |= EscapeC.NonAscii; return code; } else break; case 'x': slice = s.Left(2); if (TryParseHex(slice, out code)) { encountered |= EscapeC.BackslashX; if (code < 32) encountered |= EscapeC.Control; else if (code > 127) encountered |= EscapeC.NonAscii; s = s.Substring(2); return code; } else break; case '\\': return '\\'; case 'n': return '\n'; case 'r': return '\r'; case '0': return '\0'; case '\"': encountered |= EscapeC.DoubleQuotes; return '\"'; case '\'': encountered |= EscapeC.SingleQuotes; return '\''; case '`': encountered |= EscapeC.Quotes; return '`'; case 't': encountered |= EscapeC.Control; return '\t'; case 'a': encountered |= EscapeC.ABFV; return '\a'; case 'b': encountered |= EscapeC.ABFV; return '\b'; case 'f': encountered |= EscapeC.ABFV; return '\f'; case 'v': encountered |= EscapeC.ABFV; return '\v'; } encountered |= EscapeC.Unrecognized; s = original; return c; }
public static int UnescapeChar(ref UString s) { EscapeC _ = 0; return(UnescapeChar(ref s, ref _)); }
/// <summary>Unescapes a single character of a string. Returns the /// first character if it is not a backslash, or <c>\</c> if it is a /// backslash but no escape sequence could be discerned.</summary> /// <param name="s">Slice of a string to be unescaped. When using a /// <c>ref UString</c> overload of this method, <c>s</c> will be shorter upon /// returning from this method, as the parsed character(s) are clipped /// from the beginning (<c>s.InternalStart</c> is incremented by one /// normally and more than one in case of an escape sequence.)</param> /// <param name="encountered">Bits of this parameter are set according /// to which escape sequence is encountered, if any.</param> /// <remarks> /// This function also decodes (non-escaped) surrogate pairs. /// <para/> /// Code points with 5 or 6 digits such as \u1F4A9 are supported. /// \x escapes must be two digits and set the EscapeC.BackslashX flag. /// \u escapes must be 4 to 6 digits. If a \u escape has more than 4 /// digits, the EscapeC.HasLongEscapes flag is set. Invalid 6-digit /// escapes like \u123456 are "made valid" by being treated as 5 digits /// (the largest valid escape is <c>\u10FFFF</c>.) /// <para/> /// Supported escapes: <c>\u \x \\ \n \r \0 \' \" \` \t \a \b \f \v</c> /// </remarks> /// <example> /// EscapeC e = 0; /// UString str = @"\nfoo"; /// char c = UnescapeChar(ref str, ref e); /// Contract.Assert(str == "foo"); /// Contract.Assert(e == EscapeC.HasEscapes); /// </example> public static int UnescapeChar(ref UString s, ref EscapeC encountered) { bool fail; int c = s.PopFirst(out fail); if (c != '\\' || s.Length <= 0) { return(c); } encountered |= EscapeC.HasEscapes; int code; // hex code after \u or \x or \U int len; // length of hex code after \u or \x or \U UString slice, original = s; int type = s.PopFirst(out fail); switch (type) { case 'x': encountered |= EscapeC.BackslashX; goto case 'u'; case 'u': len = type == 'u' ? 4 : 2; slice = s.Left(len); if (TryParseHex(ref slice, out code) == len) { s = s.Substring(slice.InternalStart - s.InternalStart); if (code < 32) { encountered |= EscapeC.Control; } else if (code > 127) { encountered |= EscapeC.NonAscii; } return(code); } else { break; } case 'U': encountered |= EscapeC.HasLongEscape; slice = s.Left(6); len = TryParseHex(ref slice, out code); if (len > 0) { if (code <= 0x10FFFF) { s = s.Substring(len); } else { Debug.Assert(slice.Length == 0); // It appears to be 6 digits but only the first 5 can // be treated as part of the escape sequence. encountered |= EscapeC.HasInvalid6DigitEscape; s = s.Substring(5); code >>= 4; } if (code < 32) { encountered |= EscapeC.Control; } else if (code > 127) { encountered |= EscapeC.NonAscii; } return(code); } else { break; } case '\\': return('\\'); case 'n': return('\n'); case 'r': return('\r'); case '0': return('\0'); case '\"': encountered |= EscapeC.DoubleQuotes; return('\"'); case '\'': encountered |= EscapeC.SingleQuotes; return('\''); case '`': encountered |= EscapeC.Quotes; return('`'); case 't': encountered |= EscapeC.Control; return('\t'); case 'a': encountered |= EscapeC.ABFV; return('\a'); case 'b': encountered |= EscapeC.ABFV; return('\b'); case 'f': encountered |= EscapeC.ABFV; return('\f'); case 'v': encountered |= EscapeC.ABFV; return('\v'); } encountered |= EscapeC.Unrecognized; s = original; return(c); }
/// <summary>Unescapes a single character of a string. Returns the /// character at 'index' if it is not a backslash, or if it is a /// backslash but no escape sequence could be discerned.</summary> /// <param name="i">Current index within the string, incremented /// by one normally and more than one in case of an escape sequence.</param> /// <param name="encountered">Bits of this parameter are set according /// to which escape sequence is encountered, if any.</param> /// <exception cref="IndexOutOfRangeException">The index was invalid.</exception> /// <example> /// int i = 3; /// EscapeC e = 0; /// char c = UnescapeChar(@"foo\n", ref i, ref e); /// Contract.Assert(c == '\n' && e == EscapeC.HasEscapes); /// </example> public static char UnescapeChar(string s, ref int i, ref EscapeC encountered) { char c = s[i++]; if (c != '\\') { return(c); } encountered |= EscapeC.HasEscapes; if (i < s.Length) { int code; UString slice; switch (s[i++]) { case 'u': slice = s.Slice(i, 4); if (TryParseHex(slice, out code)) { encountered |= code < 32 ? EscapeC.Control : EscapeC.NonAscii; i += slice.Length; return((char)code); } else { break; } case 'x': slice = s.Slice(i, 2); if (TryParseHex(slice, out code)) { encountered |= code < 32 ? EscapeC.BackslashX | EscapeC.Control : EscapeC.BackslashX | EscapeC.NonAscii; i += slice.Length; return((char)code); } else { break; } case '\\': return('\\'); case 'n': return('\n'); case 'r': return('\r'); case '0': return('\0'); case '\"': encountered |= EscapeC.DoubleQuotes; return('\"'); case '\'': encountered |= EscapeC.SingleQuotes; return('\''); case '`': encountered |= EscapeC.Quotes; return('`'); case 't': encountered |= EscapeC.Control; return('\t'); case 'a': encountered |= EscapeC.ABFV; return('\a'); case 'b': encountered |= EscapeC.ABFV; return('\b'); case 'f': encountered |= EscapeC.ABFV; return('\f'); case 'v': encountered |= EscapeC.ABFV; return('\v'); default: encountered |= EscapeC.Unrecognized; i--; break; } } return(c); }
public static bool EscapeCStyle(char c, StringBuilder @out, EscapeC flags = EscapeC.Default, char quoteType = '\0') { do { if (c >= 128) { if ((flags & EscapeC.NonAscii) != 0) { EscapeU(c, @out, flags); } else { break; } } else if (c < 32) { if (c == '\n') { @out.Append(@"\n"); } else if (c == '\r') { @out.Append(@"\r"); } else if (c == '\0') { @out.Append(@"\0"); } else { if ((flags & EscapeC.ABFV) != 0) { if (c == '\a') // 7 (alert) { @out.Append(@"\a"); return(true); } if (c == '\b') // 8 (backspace) { @out.Append(@"\b"); return(true); } if (c == '\f') // 12 (form feed) { @out.Append(@"\f"); return(true); } if (c == '\v') // 11 (vertical tab) { @out.Append(@"\v"); return(true); } } if ((flags & EscapeC.Control) != 0) { if (c == '\t') { @out.Append(@"\t"); } else { EscapeU(c, @out, flags); } } else { @out.Append(c); } } } else if (c == '\"' && (flags & EscapeC.DoubleQuotes) != 0) { @out.Append("\\\""); } else if (c == '\'' && (flags & EscapeC.SingleQuotes) != 0) { @out.Append("\\'"); } else if (c == '\\') { @out.Append(@"\\"); } else { break; } return(true); } while (false); if (c == quoteType) { @out.Append('\\'); @out.Append(c); return(true); } else { @out.Append(c); return(false); } }
public static bool EscapeCStyle(char c, StringBuilder @out, EscapeC flags = EscapeC.Default, char quoteType = '\0') { if (c > 255 && (flags & (EscapeC.Unicode | EscapeC.NonAscii)) != 0) { @out.AppendFormat((IFormatProvider)null, @"\u{0:x0000}", (int)c); } else if (c == '\"' && (flags & EscapeC.DoubleQuotes) != 0) { @out.Append("\\\""); } else if (c == '\'' && (flags & EscapeC.SingleQuotes) != 0) { @out.Append("\\'"); } else if (c == quoteType) { @out.Append('\\'); @out.Append(c); } else if (c < 32) { if (c == '\n') { @out.Append(@"\n"); } else if (c == '\r') { @out.Append(@"\r"); } else if (c == '\0') { @out.Append(@"\0"); } else { if ((flags & EscapeC.ABFV) != 0) { if (c == '\a') // 7 (alert) { @out.Append(@"\a"); return(true); } if (c == '\b') // 8 (backspace) { @out.Append(@"\b"); return(true); } if (c == '\f') // 12 (form feed) { @out.Append(@"\f"); return(true); } if (c == '\v') // 11 (vertical tab) { @out.Append(@"\v"); return(true); } } if ((flags & EscapeC.Control) != 0) { if (c == '\t') { @out.Append(@"\t"); } else { @out.AppendFormat(null, @"\x{0:X2}", (int)c); } } else { @out.Append(c); } } } else if (c == '\\') { @out.Append(@"\\"); } else if (c > 127 && (flags & EscapeC.NonAscii) != 0) { @out.AppendFormat(null, @"\x{0:X2}", (int)c); } else { @out.Append(c); return(false); } return(true); }
/// <summary>Escapes characters in a string using C style, e.g. the string /// <c>"Foo\"\n"</c> maps to <c>"Foo\\\"\\\n"</c> by default.</summary> public static string EscapeCStyle(UString s, EscapeC flags = EscapeC.Default) { return EscapeCStyle(s, flags, '\0'); }
/// <summary>Writes a character <c>c</c> to a StringBuilder, either as a normal /// character or as a C-style escape sequence.</summary> /// <param name="flags">Specifies which characters should be escaped.</param> /// <param name="quoteType">Specifies a character that should always be /// escaped (typically one of <c>' " `</c>)</param> /// <returns>true if an escape sequence was emitted, false if not.</returns> /// <remarks><see cref="EscapeC.HasLongEscape"/> can be used to force a 6-digit /// unicode escape; this may be needed if the next character after this one /// is a digit.</remarks> public static bool EscapeCStyle(int c, StringBuilder @out, EscapeC flags = EscapeC.Default, char quoteType = '\0') { for(;;) { if (c >= 128) { if ((flags & EscapeC.NonAscii) != 0) { EscapeU(c, @out, flags); } else if (c >= 0xDC00) { if ((flags & EscapeC.UnicodeNonCharacters) != 0 && ( c >= 0xFDD0 && c <= 0xFDEF || // 0xFDD0...0xFDEF (c & 0xFFFE) == 0xFFFE) || // 0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, etc. (c & 0xFC00) == 0xDC00) { // 0xDC00...0xDCFF EscapeU(c, @out, flags); } else if ((flags & EscapeC.UnicodePrivateUse) != 0 && ( c >= 0xE000 && c <= 0xF8FF || c >= 0xF0000 && c <= 0xFFFFD || c >= 0x100000 && c <= 0x10FFFD)) { EscapeU(c, @out, flags); } else break; } else break; } else if (c < 32) { if (c == '\n') @out.Append(@"\n"); else if (c == '\r') @out.Append(@"\r"); else if (c == '\0') @out.Append(@"\0"); else { if ((flags & EscapeC.ABFV) != 0) { if (c == '\a') { // 7 (alert) @out.Append(@"\a"); return true; } if (c == '\b') { // 8 (backspace) @out.Append(@"\b"); return true; } if (c == '\f') { // 12 (form feed) @out.Append(@"\f"); return true; } if (c == '\v') { // 11 (vertical tab) @out.Append(@"\v"); return true; } } if ((flags & EscapeC.Control) != 0) { if (c == '\t') @out.Append(@"\t"); else EscapeU(c, @out, flags); } else @out.Append(c); } } else if (c == '\"' && (flags & EscapeC.DoubleQuotes) != 0) { @out.Append("\\\""); } else if (c == '\'' && (flags & EscapeC.SingleQuotes) != 0) { @out.Append("\\'"); } else if (c == '\\') @out.Append(@"\\"); else break; return true; } if (c == quoteType) { @out.Append('\\'); @out.Append((char)c); return true; } else @out.AppendCodePoint(c); return false; }