Могу ли я преобразовать значение строки С# в экранированный строковый литерал
В С# я могу преобразовать строковое значение в строковый литерал, как я его вижу в коде? Я хотел бы заменить вкладки, новые строки и т.д. С их escape-последовательностями.
Если этот код:
Console.WriteLine(someString);
дает:
Hello
World!
Я хочу этот код:
Console.WriteLine(ToLiteral(someString));
для создания:
\tHello\r\n\tWorld!\r\n
Ответы
Ответ 1
Я нашел это:
private static string ToLiteral(string input)
{
using (var writer = new StringWriter())
{
using (var provider = CodeDomProvider.CreateProvider("CSharp"))
{
provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
return writer.ToString();
}
}
}
Этот код:
var input = "\tHello\r\n\tWorld!";
Console.WriteLine(input);
Console.WriteLine(ToLiteral(input));
Выдает:
Hello
World!
"\tHello\r\n\tWorld!"
Ответ 2
Как насчет Regex.Escape(String)?
Regex.Escape избегает минимального набора символов (\, *, +,?, |, {, [, (,), ^, $,., # и пустое пространство), заменив их их побегом коды.
Ответ 3
EDIT: более структурированный подход, включая все escape-последовательности для string
и char
s.
Не заменяет символы Unicode их буквальным эквивалентом.
Также не готовит яйца.
public class ReplaceString
{
static readonly IDictionary<string, string> m_replaceDict
= new Dictionary<string, string>();
const string ms_regexEscapes = @"[\a\b\f\n\r\t\v\\""]";
public static string StringLiteral(string i_string)
{
return Regex.Replace(i_string, ms_regexEscapes, match);
}
public static string CharLiteral(char c)
{
return c == '\'' ? @"'\''" : string.Format("'{0}'", c);
}
private static string match(Match m)
{
string match = m.ToString();
if (m_replaceDict.ContainsKey(match))
{
return m_replaceDict[match];
}
throw new NotSupportedException();
}
static ReplaceString()
{
m_replaceDict.Add("\a", @"\a");
m_replaceDict.Add("\b", @"\b");
m_replaceDict.Add("\f", @"\f");
m_replaceDict.Add("\n", @"\n");
m_replaceDict.Add("\r", @"\r");
m_replaceDict.Add("\t", @"\t");
m_replaceDict.Add("\v", @"\v");
m_replaceDict.Add("\\", @"\\");
m_replaceDict.Add("\0", @"\0");
//The SO parser gets fooled by the verbatim version
//of the string to replace - @"\"""
//so use the 'regular' version
m_replaceDict.Add("\"", "\\\"");
}
static void Main(string[] args){
string s = "here a \"\n\tstring\" to test";
Console.WriteLine(ReplaceString.StringLiteral(s));
Console.WriteLine(ReplaceString.CharLiteral('c'));
Console.WriteLine(ReplaceString.CharLiteral('\''));
}
}
Ответ 4
public static class StringHelpers
{
private static Dictionary<string, string> escapeMapping = new Dictionary<string, string>()
{
{"\"", @"\\\"""},
{"\\\\", @"\\"},
{"\a", @"\a"},
{"\b", @"\b"},
{"\f", @"\f"},
{"\n", @"\n"},
{"\r", @"\r"},
{"\t", @"\t"},
{"\v", @"\v"},
{"\0", @"\0"},
};
private static Regex escapeRegex = new Regex(string.Join("|", escapeMapping.Keys.ToArray()));
public static string Escape(this string s)
{
return escapeRegex.Replace(s, EscapeMatchEval);
}
private static string EscapeMatchEval(Match m)
{
if (escapeMapping.ContainsKey(m.Value))
{
return escapeMapping[m.Value];
}
return escapeMapping[Regex.Escape(m.Value)];
}
}
Ответ 5
попробовать:
var t = HttpUtility.JavaScriptStringEncode(s);
Ответ 6
Полностью работающая реализация, включая экранирование символов Unicode и ASCII, не подлежащих печати. Не вставляет знаки "+", такие как ответ Hallgrim.
static string ToLiteral(string input) {
StringBuilder literal = new StringBuilder(input.Length + 2);
literal.Append("\"");
foreach (var c in input) {
switch (c) {
case '\'': literal.Append(@"\'"); break;
case '\"': literal.Append("\\\""); break;
case '\\': literal.Append(@"\\"); break;
case '\0': literal.Append(@"\0"); break;
case '\a': literal.Append(@"\a"); break;
case '\b': literal.Append(@"\b"); break;
case '\f': literal.Append(@"\f"); break;
case '\n': literal.Append(@"\n"); break;
case '\r': literal.Append(@"\r"); break;
case '\t': literal.Append(@"\t"); break;
case '\v': literal.Append(@"\v"); break;
default:
// ASCII printable character
if (c >= 0x20 && c <= 0x7e) {
literal.Append(c);
// As UTF16 escaped character
} else {
literal.Append(@"\u");
literal.Append(((int)c).ToString("x4"));
}
break;
}
}
literal.Append("\"");
return literal.ToString();
}
Ответ 7
Ответ Hallgrim превосходный, но дополнения "+", "новая линия" и "отступ" нарушали функциональность для меня. Легкий способ:
private static string ToLiteral(string input)
{
using (var writer = new StringWriter())
{
using (var provider = CodeDomProvider.CreateProvider("CSharp"))
{
provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, new CodeGeneratorOptions {IndentString = "\t"});
var literal = writer.ToString();
literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");
return literal;
}
}
}
Ответ 8
Интересный вопрос.
Если вы не можете найти лучший метод, вы всегда можете заменить.
В случае, если вы выбираете это, вы можете использовать этот С# Escape Sequence List:
- \'- одинарная кавычка, необходимая для символьных литералов
- \"- двойная кавычка, необходимая для строковых литералов
- \- обратная косая черта
- \0 - Юникод символ 0
- \a - Оповещение (персонаж 7)
- \b - Backspace (символ 8)
- \f - подача формы (символ 12)
- \n - Новая строка (символ 10)
- \r - возврат каретки (символ 13)
- \t - Горизонтальная вкладка (символ 9)
- \v - Вертикальная кавычка (символ 11)
- \uxxxx - escape-последовательность Unicode для символа с шестнадцатеричным значением xxxx
- \xn [n] [n] [n] - escape-последовательность Юникода для символа с шестнадцатеричным значением nnnn (версия переменной длины \uxxxx)
- \Uxxxxxxxx - escape-последовательность Unicode для символа с шестнадцатеричным значением xxxxxxxx (для генерации суррогатов)
Этот список можно найти в С# Часто задаваемые вопросы. Какие доступны escape-последовательности символов?
Ответ 9
Ниже приведено небольшое улучшение для ответа Smilediver, оно не избежит всех символов без ASCII, но только они действительно необходимы.
using System;
using System.Globalization;
using System.Text;
public static class CodeHelper
{
public static string ToLiteral(this string input)
{
var literal = new StringBuilder(input.Length + 2);
literal.Append("\"");
foreach (var c in input)
{
switch (c)
{
case '\'': literal.Append(@"\'"); break;
case '\"': literal.Append("\\\""); break;
case '\\': literal.Append(@"\\"); break;
case '\0': literal.Append(@"\0"); break;
case '\a': literal.Append(@"\a"); break;
case '\b': literal.Append(@"\b"); break;
case '\f': literal.Append(@"\f"); break;
case '\n': literal.Append(@"\n"); break;
case '\r': literal.Append(@"\r"); break;
case '\t': literal.Append(@"\t"); break;
case '\v': literal.Append(@"\v"); break;
default:
if (Char.GetUnicodeCategory(c) != UnicodeCategory.Control)
{
literal.Append(c);
}
else
{
literal.Append(@"\u");
literal.Append(((ushort)c).ToString("x4"));
}
break;
}
}
literal.Append("\"");
return literal.ToString();
}
}
Ответ 10
public static class StringEscape
{
static char[] toEscape = "\0\x1\x2\x3\x4\x5\x6\a\b\t\n\v\f\r\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\"\\".ToCharArray();
static string[] literals = @"\0,\x0001,\x0002,\x0003,\x0004,\x0005,\x0006,\a,\b,\t,\n,\v,\f,\r,\x000e,\x000f,\x0010,\x0011,\x0012,\x0013,\x0014,\x0015,\x0016,\x0017,\x0018,\x0019,\x001a,\x001b,\x001c,\x001d,\x001e,\x001f".Split(new char[] { ',' });
public static string Escape(this string input)
{
int i = input.IndexOfAny(toEscape);
if (i < 0) return input;
var sb = new System.Text.StringBuilder(input.Length + 5);
int j = 0;
do
{
sb.Append(input, j, i - j);
var c = input[i];
if (c < 0x20) sb.Append(literals[c]); else sb.Append(@"\").Append(c);
} while ((i = input.IndexOfAny(toEscape, j = ++i)) > 0);
return sb.Append(input, j, input.Length - j).ToString();
}
}
Ответ 11
Моя попытка добавить ToVerbatim к Hallgrim's принятому ответу выше:
private static string ToLiteral(string input)
{
using (var writer = new StringWriter())
{
using (var provider = CodeDomProvider.CreateProvider("CSharp"))
{
provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, new CodeGeneratorOptions { IndentString = "\t" });
var literal = writer.ToString();
literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");
return literal;
}
}
}
private static string ToVerbatim( string input )
{
string literal = ToLiteral( input );
string verbatim = "@" + literal.Replace( @"\r\n", Environment.NewLine );
return verbatim;
}
Ответ 12
Если соглашений JSON достаточно для неэкранированных строк, которые вы хотите экранировать, и вы уже используете Newtonsoft.Json
в своем проекте (он имеет довольно большие накладные расходы), вы можете использовать этот пакет, как Newtonsoft.Json
ниже:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
Console.WriteLine(ToLiteral( @"abc\n123") );
}
private static string ToLiteral(string input){
return JsonConvert.DeserializeObject<string>("\"" + input + "\"");
}
}
Ответ 13
Я отправляю свою собственную реализацию, которая обрабатывает значения null
и должна быть более эффективной из-за использования таблиц поиска массивов, ручного шестнадцатеричного преобразования и исключения инструкций switch
.
using System;
using System.Text;
using System.Linq;
public static class StringLiteralEncoding {
private static readonly char[] HEX_DIGIT_LOWER = "0123456789abcdef".ToCharArray();
private static readonly char[] LITERALENCODE_ESCAPE_CHARS;
static StringLiteralEncoding() {
// Per http://msdn.microsoft.com/en-us/library/h21280bw.aspx
var escapes = new string[] { "\aa", "\bb", "\ff", "\nn", "\rr", "\tt", "\vv", "\"\"", "\\\\", "??", "\00" };
LITERALENCODE_ESCAPE_CHARS = new char[escapes.Max(e => e[0]) + 1];
foreach(var escape in escapes)
LITERALENCODE_ESCAPE_CHARS[escape[0]] = escape[1];
}
/// <summary>
/// Convert the string to the equivalent C# string literal, enclosing the string in double quotes and inserting
/// escape sequences as necessary.
/// </summary>
/// <param name="s">The string to be converted to a C# string literal.</param>
/// <returns><paramref name="s"/> represented as a C# string literal.</returns>
public static string Encode(string s) {
if(null == s) return "null";
var sb = new StringBuilder(s.Length + 2).Append('"');
for(var rp = 0; rp < s.Length; rp++) {
var c = s[rp];
if(c < LITERALENCODE_ESCAPE_CHARS.Length && '\0' != LITERALENCODE_ESCAPE_CHARS[c])
sb.Append('\\').Append(LITERALENCODE_ESCAPE_CHARS[c]);
else if('~' >= c && c >= ' ')
sb.Append(c);
else
sb.Append(@"\x")
.Append(HEX_DIGIT_LOWER[c >> 12 & 0x0F])
.Append(HEX_DIGIT_LOWER[c >> 8 & 0x0F])
.Append(HEX_DIGIT_LOWER[c >> 4 & 0x0F])
.Append(HEX_DIGIT_LOWER[c & 0x0F]);
}
return sb.Append('"').ToString();
}
}
Ответ 14
Код:
string someString1 = "\tHello\r\n\tWorld!\r\n";
string someString2 = @"\tHello\r\n\tWorld!\r\n";
Console.WriteLine(someString1);
Console.WriteLine(someString2);
Вывод:
Hello
World!
\tHello\r\n\tWorld!\r\n
Это то, что вы хотите?