ฉันสามารถแปลงค่าสตริง C # เป็นสตริงตัวอักษรที่ใช้ Escape


196

ใน C # ฉันสามารถแปลงค่าสตริงเป็นตัวอักษรสตริงตามที่ฉันเห็นในโค้ดได้หรือไม่ ฉันต้องการแทนที่แท็บบรรทัดใหม่ ฯลฯ ด้วยลำดับการหลีกเลี่ยง

หากรหัสนี้:

Console.WriteLine(someString);

ผลิต:

Hello
World!

ฉันต้องการรหัสนี้:

Console.WriteLine(ToLiteral(someString));

ผลิต:

\tHello\r\n\tWorld!\r\n

คำตอบ:


181

ฉันพบสิ่งนี้:

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!"

1
เพิ่งพบสิ่งนี้จาก google เรื่อง สิ่งนี้จะต้องดีที่สุดไม่มีประเด็นในการคิดค้นสิ่งใหม่ที่. net สามารถทำเพื่อเราได้
Andy Morris

16
Nice หนึ่ง แต่โปรดทราบว่าสำหรับสตริงที่ยาวกว่านี้จะแทรกตัวดำเนินการ "+" บรรทัดใหม่และการเยื้อง ฉันหาทางปิดไม่ได้
Timwi

2
แล้วอินเวอร์สล่ะ? หากคุณมีไฟล์ที่มีข้อความที่มีลำดับเอสเคปรวมถึงตัวอักษรพิเศษที่หนีออกมาพร้อมกับรหัส ascii? วิธีผลิตเวอร์ชันดิบ?
Luciano

1
หากคุณเรียกใช้: void Main () {Console.WriteLine (ToLiteral ("test \" \ '\\ 0 \ a \ b \ f \ n \ r \ t \ v \ uaaaa \\\ blah "));} คุณจะสังเกตเห็นว่านี่ไม่ได้ช่วยให้รอดพ้นมาได้บ้าง Ronnie Overby ชี้ให้เห็น \ f คนอื่นคือ \ a และ \ b
costa

4
มีวิธีที่จะทำให้มันออกคำต่อคำ@"..."ตัวอักษร( )?
rookie1024

39

แล้วRegex.Escape (String)ล่ะ?

Regex.Escape หนีชุดอักขระขั้นต่ำ (\, *, +,?, |, {, [, (,), ^, $,., #, และ white space) โดยแทนที่ด้วยรหัสการยกเว้น


6
+1 ไม่ทราบว่าทำไมถึงเป็นเช่นนี้ คำตอบอื่น ๆ นั้นละเอียดเกินไปและดูเหมือนกับล้อที่สามารถปรับเปลี่ยนได้
Adriano Carneiro

40
นี่ไม่ใช่สิ่งที่ OP ขอมา มันจะไม่ส่งคืนสตริงตามตัวอักษร แต่จะส่งคืนสตริงที่มีอักขระพิเศษของ Regex สิ่งนี้จะกลายHello World?เป็นHello World\?แต่นั่นเป็นสตริงตัวอักษรที่ไม่ถูกต้อง
atheaos

2
ฉันเห็นด้วยกับ @atheaos นี่เป็นคำตอบที่ดีสำหรับคำถามที่แตกต่างกันมาก
hypehuman

5
+1 แม้ว่ามันจะไม่ตอบคำถามของ OP มันเป็นสิ่งที่ฉัน (และดังนั้นฉันสงสัยว่าคนอื่นอาจ) กำลังมองหาเมื่อฉันเจอคำถามนี้ :)
GazB

สิ่งนี้จะไม่ทำงานตามที่ต้องการ อักขระพิเศษ regex ไม่เหมือนกัน มันจะใช้ได้กับ \ n ตัวอย่างเช่น แต่เมื่อคุณมีที่ว่างมันจะถูกแปลงเป็น "\" ซึ่งไม่ใช่สิ่งที่ C # จะทำ ...
Ernesto

25

แก้ไข: วิธีการที่มีโครงสร้างมากขึ้นรวมถึงลำดับหนีทั้งหมดสำหรับstrings และchars
ไม่แทนที่อักขระ 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's a \"\n\tstring\" to test";
        Console.WriteLine(ReplaceString.StringLiteral(s));
        Console.WriteLine(ReplaceString.CharLiteral('c'));
        Console.WriteLine(ReplaceString.CharLiteral('\''));

    }
}

นี่ไม่ใช่ลำดับการหลบหนีทั้งหมด)
TcKs

1
ทำงานได้ดีกว่าโซลูชันด้านบนและคุณสามารถเพิ่มลำดับการหลีกเลี่ยงอื่น ๆ ได้อย่างง่ายดาย
Arno Peters

คำต่อคำในคำตอบที่ยอมรับก็คือการขับรถให้ฉัน ใช้งานได้ 100% เพื่อจุดประสงค์ของฉัน แทนที่ regex ด้วย@"[\a\b\f\n\r\t\v\\""/]"และเสริมสำหรับm_replaceDict.Add("/", @"\/"); JSON
น่าสนใจชื่อที่นี่

นอกจากนี้คุณต้องเพิ่มใบเสนอราคาที่แนบมานี้หากคุณต้องการ
น่าสนใจชื่อที่นี่

19

ลอง:

var t = HttpUtility.JavaScriptStringEncode(s);

ไม่ทำงาน, ไม่เป็นผล. หากฉันมี "abc \ n123" (ไม่มีเครื่องหมายคำพูด 8 ตัวอักษร) ฉันต้องการ "abc" + \ n + "123" (7 ตัวอักษร) แต่จะสร้าง "abc" + "\\" + "\ n123" (9 ตัวอักษร) สังเกตุว่าเครื่องหมายสแลชนั้นเพิ่มเป็นสองเท่าและยังคงมีสตริงตัวอักษร "\ n" เป็นอักขระสองตัวไม่ใช่อักขระที่ใช้ Escape
Paul

2
@ พอลสิ่งที่คุณต้องการอยู่ตรงข้ามกับคำถามที่ถาม ตามคำอธิบายของคุณตอบคำถามแล้วจึงใช้งานได้
คดีของกองทุนโมนิกา

ฉันพบว่ามีประโยชน์ในการหลีกเลี่ยงชื่อไดเรกทอรีที่ใช้งานในส่วนหน้า
chakeda

19
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)];
    }
}

1
เหตุใดจึงมี 3 แบ็กสแลชและเครื่องหมายคำพูดสองตัวในค่าแรกของพจนานุกรม
James Yeoman

คำตอบที่ดี @JamesYeoman นั่นเป็นเพราะรูปแบบ regex จำเป็นต้องหลบหนี
Ali Mousavi Kherad

18

การติดตั้งใช้งานได้อย่างสมบูรณ์รวมถึงการหลีกเลี่ยง 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();
    }

2
คุณควรใช้Char.GetUnicodeCategory(c) == UnicodeCategory.Controlเพื่อตัดสินใจว่าจะหลบหนีมิฉะนั้นคนที่ไม่พูด ASCII จะไม่มีความสุขมาก
Deerchao

ขึ้นอยู่กับสถานการณ์หากสตริงผลลัพธ์ของคุณจะถูกใช้ในสภาพแวดล้อมที่สนับสนุนยูนิโค้ดหรือไม่
Smilediver

ฉันเพิ่มinput = input ?? string.Empty;เป็นบรรทัดแรกของวิธีการดังนั้นฉันสามารถผ่านnullและรับกลับมา""แทนที่จะเป็นข้อยกเว้นอ้างอิงโมฆะ
Andy

ดี เปลี่ยนเครื่องหมายคำพูดล้อมรอบเป็น'ตอนนี้คุณมีสิ่งที่ Python มอบให้กับคุณด้วยrepr(a_string):)
z33k

17

คำตอบของ 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;
        }
    }
}

ใช้งานได้ดี ฉันยังเพิ่มสายหนึ่งก่อนที่return literalจะทำให้มันสามารถอ่านเพิ่มเติมได้ที่: literal = literal.Replace("\\r\\n", "\\r\\n\"+\r\n\"");
บ๊อบ

เพิ่มสิ่งนี้literal = literal.Replace("/", @"\/");สำหรับJSONฟังก์ชั่น
น่าสนใจชื่อที่นี่

นี่คือ 100% ตรงไปข้างหน้าและคำตอบที่ถูกต้องเท่านั้น! คำตอบอื่น ๆ ทั้งหมดไม่เข้าใจคำถามหรือคิดค้นวงล้อใหม่
bytecode77

เศร้าไม่สามารถให้เรื่องนี้ทำงานภายใต้ DOTNET CORE ได้ ใครมีคำตอบที่ดีกว่า
sk

8

นี่คือการปรับปรุงเล็กน้อยสำหรับคำตอบของ 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();
    }
}

8

คำถามที่น่าสนใจ

หากคุณไม่พบวิธีที่ดีกว่าคุณสามารถแทนที่ได้เสมอ
ในกรณีที่คุณเลือกใช้คุณสามารถใช้รายการC # Escape Sequence นี้ :

  • \ '- เครื่องหมายคำพูดเดี่ยวจำเป็นสำหรับตัวอักษรตัวอักษร
  • \ "- เครื่องหมายคำพูดคู่จำเป็นสำหรับตัวอักษรสตริง
  • \ - แบ็กสแลช
  • \ 0 - อักขระ Unicode 0
  • \ a - แจ้งเตือน (ตัวละคร 7)
  • \ b - Backspace (อักขระ 8)
  • \ f - ฟีดฟอร์ม (อักขระ 12)
  • \ n - บรรทัดใหม่ (อักขระ 10)
  • \ r - Carriage return (ตัวละคร 13)
  • \ t - แท็บแนวนอน (อักขระ 9)
  • \ v - เครื่องหมายคำพูดแนวตั้ง (อักขระ 11)
  • \ uxxxx - ลำดับ Unicode สำหรับอักขระที่มีค่าฐานสิบหก xxxx
  • \ xn [n] [n] [n] - ลำดับ Unicode สำหรับอักขระที่มีค่าฐานสิบหก nnnn (รุ่นความยาวผันแปรของ \ uxxxx)
  • \ Uxxxxxxxx - ลำดับ Unicode สำหรับอักขระที่มีค่าฐานสิบหก xxxxxxxx (สำหรับการสร้างตัวแทน)

รายการนี้สามารถพบได้ในคำถามที่พบบ่อย C # ลำดับการหลบหนีของตัวละครมีอะไรบ้าง


2
ลิงก์นี้ใช้งานไม่ได้อีกต่อไปตัวอย่างตำราที่ว่าทำไมคำตอบสำหรับลิงค์เท่านั้นจึงไม่หมด
James

จริงมาก @James แต่ต้องขอบคุณ Jamie Twells ข้อมูลนี้สามารถใช้ได้อีก: +1:
Nelson Reis

5

มีวิธีการนี้ในแพคเกจMicrosoft.CodeAnalysis.CSharpของ Roslyn บน nuget:

    private static string ToLiteral(string valueTextForCompiler)
    {
        return Microsoft.CodeAnalysis.CSharp.SymbolDisplay.FormatLiteral(valueTextForCompiler, false);
    }

เห็นได้ชัดว่าสิ่งนี้ไม่มีอยู่ในช่วงเวลาของคำถามเดิม แต่อาจช่วยให้ผู้คนที่จบลงที่นี่จาก Google


3

หากข้อกำหนด JSON นั้นเพียงพอสำหรับสตริงที่ไม่ใช้ค่า Escape ที่คุณต้องการหลบหนีและคุณใช้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 + "\"");
    }
}

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

2

ความพยายามของฉันในการเพิ่ม ToVerbatim ไปยังคำตอบที่ยอมรับของ 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;
        }
    }
}

private static string ToVerbatim( string input )
{
    string literal = ToLiteral( input );
    string verbatim = "@" + literal.Replace( @"\r\n", Environment.NewLine );
    return verbatim;
}

1

คำตอบของ Hallgrim นั้นยอดเยี่ยม นี่คือการปรับแต่งเล็กน้อยในกรณีที่คุณต้องการแยกอักขระช่องว่างเพิ่มเติมและการกระจายบรรทัดด้วยนิพจน์ทั่วไปของ ac # ฉันต้องการสิ่งนี้ในกรณีของค่า Json ที่ต่อเนื่องกันสำหรับการแทรกลงในแผ่นงาน Google และพบปัญหาเนื่องจากโค้ดแทรกแท็บ + ช่องว่าง ฯลฯ

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

-7

รหัส:

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

นี่คือสิ่งที่คุณต้องการ?


ฉันมี someString1 แต่อ่านจากไฟล์ ฉันต้องการให้ปรากฏเป็น someString2 หลังจากเรียกวิธีการบางอย่าง
Hallgrim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.