C # 문자열 값을 이스케이프 된 문자열 리터럴로 변환 할 수 있습니까


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
구글에서 주제를 찾았습니다. 이것은 .net이 우리를 위해 할 수있는 것들을 재창조하는 데있어 최고의 것이되어야합니다
Andy Morris

16
좋은 점이지만 더 긴 문자열의 경우 "+"연산자, 줄 바꿈 및 들여 쓰기가 삽입됩니다. 끄는 방법을 찾지 못했습니다.
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 (문자열) ?

Regex.Escape는 이스케이프 코드로 대체하여 최소 문자 세트 (\, *, +,?, |, {, [, (,), ^, $,., # 및 공백)를 이스케이프합니다.


6
왜 이것이 아래인지 +1 모르겠다. 다른 답변은 너무 장황하고 바퀴를 재발견하는 것처럼 보입니다
Adriano Carneiro

40
이것은 OP가 요구하는 것이 아닙니다. 문자열 리터럴을 반환하지 않으며 Regex 특수 문자가 이스케이프 된 문자열을 반환합니다. 이 될지는 Hello World?으로 Hello World\?, 그러나 그것은 잘못된 문자열 리터럴입니다.
atheaos

2
@atheaos에 동의합니다. 이것은 매우 다른 질문에 대한 훌륭한 답변입니다.
hypehuman

5
+1 OP의 질문에 대답하지는 못했지만이 질문을 만났을 때 내가 찾은 것이 었습니다. :)
GazB 2016 년

필요에 따라 작동하지 않습니다. 정규식 특수 문자는 동일하지 않습니다. 예를 들어 \ n에서 작동하지만 공백이 있으면 C #이 수행하지 않는 "\"로 변환됩니다.
Ernesto

25

편집 : strings 및 chars에 대한 모든 이스케이프 시퀀스를 포함하여보다 체계적인 접근 방식 .
유니 코드 문자를 해당 문자로 대체하지 않습니다. 계란도 요리하지 않습니다.

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

받아 들인 대답의 Verbatim은 저를 실책하게 만들었습니다. 이것은 내 목적으로 100 % 작동합니다. 정규식을로 대체 @"[\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"문자열 리터럴을 포함합니다.
Paul

2
@Paul 원하는 것은 질문이하는 것과 반대입니다. 이것은 귀하의 설명에 따라 질문에 대답하므로 작동 합니다.
Fund Monica의 소송

프론트 엔드에서 활성 디렉토리 이름을 피하는 것이 유용하다는 것을
알았습니다.

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 개의 백 슬래시와 2 개의 음성 표시가있는 이유는 무엇입니까?
James Yeoman

정답은 @JamesYeoman입니다. 정규식 패턴을 이스케이프해야하기 때문입니다.
알리 Mousavi Kherad

18

유니 코드 및 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

null 참조 예외 대신 input = input ?? string.Empty;전달 null하고 다시 얻을 수 있도록 메서드의 첫 번째 줄로 추가 했습니다 "".
Andy

좋은. 묶는 따옴표를 변경 '하면 이제 파이썬에서 제공하는 내용이 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\"");
Bob

기능을 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 # 탈출 시퀀스 목록을 사용할 수 있습니다 :

  • \ '-문자 리터럴에 필요한 작은 따옴표
  • \ "-큰 따옴표, 문자열 리터럴에 필요
  • 백 슬래시
  • \ 0-유니 코드 문자 0
  • \ a-경고 (문자 7)
  • \ b-백 스페이스 (문자 8)
  • \ f-용지 공급 (문자 12)
  • \ n-줄 바꾸기 (문자 10)
  • \ r-캐리지 리턴 (문자 13)
  • \ t-가로 탭 (문자 9)
  • \ v-세로 따옴표 (문자 11)
  • \ uxxxx-16 진수 값이 xxxx 인 문자의 유니 코드 이스케이프 시퀀스
  • \ xn [n] [n] [n]-16 진수 값이 nnnn 인 문자의 유니 코드 이스케이프 시퀀스 (가변 길이 버전 \ uxxxx)
  • \ Uxxxxxxxx-16 진수 값이 xxxxxxxx 인 문자의 유니 코드 이스케이프 시퀀스 (대리인 생성 용)

이 목록은 C # FAQ에서 찾을 수 있습니다. 어떤 문자 이스케이프 시퀀스를 사용할 수 있습니까?


2
링크 전용 답변이 권장되지 않는 교과서의 예인이 링크는 더 이상 작동하지 않습니다.
James

@James는 매우 사실이지만 Jamie Twells 덕분에 정보를 다시 이용할 수 있습니다. +1 :
Nelson Reis

5

nuget 의 Roslyn 's Microsoft.CodeAnalysis.CSharp 패키지 에는이를위한 방법이 있습니다 .

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

분명히 이것은 원래 질문 당시에는 존재하지 않았지만 Google에서 온 사람들에게 도움이 될 수 있습니다.


3

이스케이프 처리되지 않은 문자열에 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 + "\"");
    }
}

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

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

1

Hallgrim의 대답은 훌륭했습니다. ac # 정규 표현식으로 추가 공백 문자와 줄 바꿈을 구문 분석해야 할 경우를 대비하여 약간의 조정이 있습니다. Google 시트에 삽입하기 위해 직렬화 된 Json 값의 경우이가 필요했으며 코드가 탭, +, 공백 등을 삽입 할 때 문제가 발생했습니다.

  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값 을 처리 하고 배열 조회 테이블 사용, 수동 16 진수 변환 및 회피 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.