我能否将C#字符串值转换为转义字符串字面量?

228
在C#中,我可以将字符串值转换为字符串字面值吗?即像在代码中看到的那样?我想用它们的转义序列替换制表符、换行符等。
如果这段代码:
Console.WriteLine(someString);

生成:

Hello
World!

我想要这段代码:

Console.WriteLine(ToLiteral(someString));

生成:

\tHello\r\n\tWorld!\r\n
16个回答

4
如果JSON约定足以转义您想要转义的非转义字符串,并且您已经在项目中使用Json.NETNewtonsoft.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 + "\"");
    }
}

这似乎与 OP 想要的相反?不过 JsonConvert.SerializeObject(input).Trim('"') 运行得很好。 - Jonathan Amend

2

我尝试在Hallgrim的被接受答案中添加ToVerbatim:

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;
}

2
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();
  }
}

需要解释一下。例如,这个想法/主旨是什么?例如,是出于性能考虑吗?请通过编辑您的答案来回复,而不是在评论中回复(不要包含“编辑:”,“更新:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen

1

Hallgrim's answer非常好。如果您需要使用C#正则表达式解析额外的空格字符和换行符,这里有一个小调整。我在将序列化的JSON值插入Google Sheets时遇到了问题,因为代码插入了制表符、+号、空格等。

  provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
  var literal = writer.ToString();
  var r2 = new Regex(@"\"" \+.\n[\s]+\""", RegexOptions.ECMAScript);
  literal = r2.Replace(literal, "");
  return literal;

-1

我提交了自己的实现,它处理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();
  }
}

为什么switch语句不好?它们不是由编译器进行优化(查找表或类似)吗? - Peter Mortensen

-10

代码:

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

1
我有一个someString1,但它是从文件中读取的。在调用某个方法后,我希望它出现为someString2。 - Hallgrim
字符串可能是动态创建/获取的,他需要一个处理任何字符串的方法。 - rufw91

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接