다음을 통해 공유


원시 문자열 리터럴

메모

이 문서는 기능 사양입니다. 사양은 기능의 디자인 문서 역할을 합니다. 여기에는 기능 디자인 및 개발 중에 필요한 정보와 함께 제안된 사양 변경 내용이 포함됩니다. 이러한 문서는 제안된 사양 변경이 완료되고 현재 ECMA 사양에 통합될 때까지 게시됩니다.

기능 사양과 완료된 구현 간에 약간의 불일치가 있을 수 있습니다. 이러한 차이는관련 LDM(언어 디자인 모임) 노트에서 캡처됩니다.

사양문서에서 기능 사양서가 C# 언어 표준에 채택되는 과정에 대해 자세히 알아볼 수 있습니다.

요약

최소 세 개의 """ 문자로 시작하고(최대 개수 제한 없음), 선택적으로 new_line뒤에 문자열 내용이 올 수 있으며, 리터럴이 시작한 것과 동일한 수의 따옴표로 끝나는 새로운 형식의 문자열 리터럴을 허용합니다. 예를 들어:

var xml = """
          <element attr="content"/>
          """;

중첩된 콘텐츠 자체가 """ 사용하려고 할 수 있으므로 시작/끝 구분 기호는 다음과 같이 더 길어질 수 있습니다.

var xml = """"
          Ok to use """ here
          """";

개발자가 코드에서 좋아하는 들여쓰기를 허용하고 텍스트를 쉽게 읽을 수 있도록 하기 위해, 이러한 문자열 리터럴은 최종 리터럴 값을 생성할 때 마지막 줄에 지정된 들여쓰기를 자연스럽게 제거합니다. 예를 들어 다음 형식의 리터럴은 다음과 같습니다.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

다음 콘텐츠가 포함됩니다.

<element attr="content">
  <body>
  </body>
</element>

이렇게 하면 원하는 리터럴을 생성하면서 코드가 자연스럽게 보일 수 있으며 특수 문자열 조작 루틴을 사용해야 하는 경우 런타임 비용을 방지할 수 있습니다.

들여쓰기 동작을 원하지 않는 경우 다음과 같이 사용하지 않도록 설정하는 것도 간단합니다.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

한 줄 양식도 지원됩니다. 최소 3개의 """ 문자(최대값 없음), 문자열 내용(new_line 문자를 포함할 수 없음)으로 시작한 다음 리터럴이 시작한 것과 동일한 수의 따옴표로 끝납니다. 예를 들어:

var xml = """<summary><element attr="content"/></summary>""";

보간된 원시 문자열도 지원됩니다. 이 경우 문자열은 보간을 시작하는 데 필요한 중괄호 수를 지정합니다(리터럴의 시작 부분에 있는 달러 기호 수에 따라 결정됨). 중괄호의 수가 더 적은 중괄호 시퀀스는 콘텐츠로만 처리됩니다. 예를 들어:

var json = $$"""
             {
                "summary": "text",
                "length" : {{value.Length}},
             };
             """;

동기

C#에는 임의의 텍스트를 효과적으로 포함할 수 있는 간단한 문자열 리터럴을 만드는 일반적인 방법이 없습니다. 현재 모든 C# 문자열 리터럴 형식은 내용에 특수 문자를 포함하는 경우(구분 기호를 항상 사용하는 경우) 반드시 적절한 방식으로 이스케이프 처리가 필요합니다. 이렇게 하면 다른 언어(예: XML, HTML 또는 JSON 리터럴)를 포함하는 리터럴을 쉽게 사용할 수 없습니다.

현재 C#에서 이러한 리터럴을 형성하는 모든 현재 방법은 항상 사용자가 수동으로 콘텐츠를 이스케이프하도록 강제합니다. 지금 이 순간 편집은 매우 성가실 수 있습니다. 이스케이핑은 콘텐츠에서 발생할 때마다 회피할 수 없고 처리해야 하기 때문입니다. 이것은 특히 따옴표 또는 백슬래시를 포함하는 경우, regexes에 대해 특히 고통스럽습니다. 축자(@"") 문자열이 있더라도 따옴표 자체를 이스케이프하여 C#과 regex가 섞여 있어야 합니다. {} 보간된($"") 문자열에서도 마찬가지로 실망스럽습니다.

문제의 핵심은 모든 문자열에 고정된 시작/끝 구분 기호가 있다는 것입니다. 그렇다면 문자열 내용에서 끝 구분 기호를 명시해야 할 필요가 있을 수 있으므로, 항상 이스케이프 메커니즘이 필요합니다. 구분 기호 " 많은 언어에서 매우 일반적이므로 특히 문제가 됩니다.

이 문제를 해결하기 위해 이 제안을 통해 문자열의 내용과 충돌하지 않는 방식으로 항상 만들 수 있도록 유연한 시작 및 끝 구분 기호를 사용할 수 있습니다.

목표

  1. 이스케이프 시퀀스를 필요 없이 사용자가 모든 문자열 값을 제공할 수 있도록 메커니즘을 제공합니다. 모든 문자열은 이스케이프 시퀀스 없이 표시할 수 있어야 하므로 사용자가 텍스트 내용과 충돌하지 않도록 보장되는 구분 기호를 항상 지정할 수 있어야 합니다.
  2. 동일한 방식으로 인터폴레이션을 지원합니다. 위와 같이 모든 문자열은 이스케이프 없이 표시할 수 있어야 하므로 사용자가 텍스트 내용과 충돌하지 않도록 보장되는 interpolation 구분 기호를 항상 지정할 수 있어야 합니다. 중요한 것은 보간 구분 기호({})를 사용하는 언어가 첫 번째 등급으로 느껴지고 사용하기가 불편하지 않아야 한다는 것입니다.
  3. 여러 줄 문자열 리터럴은 코드에서 보기 좋게 표시되어야 하며 컴파일 단위 내의 들여쓰기가 어색해 보이게 해서는 안 됩니다. 중요한 것은 들여쓰기가 없는 리터럴 값이 파일의 첫 번째 열을 차지하도록 강요해서는 안 됩니다. 이 값은 코드 흐름을 끊을 수 있으며 이를 둘러싸는 나머지 코드와 정렬되지 않은 것처럼 보일 수 있습니다.
    • 이 동작은 리터럴을 명확하고 쉽게 읽을 수 있도록 유지하면서도 쉽게 재정의할 수 있어야 합니다.
  4. 자체에 new_line을 포함하지 않거나, 따옴표(") 문자로 시작하거나 끝나지 않는 모든 문자열의 경우, 문자열 리터럴 자체를 한 줄로 나타낼 수 있어야 합니다.
    • 필요하다면, 복잡성을 추가하여 다음과 같이 명확히 할 수 있습니다: new_line을 포함하지 않는 모든 문자열에 대해, 시작하거나 끝에 따옴표 " 문자를 포함할 수 있지만, 문자열 리터럴 자체를 한 줄로 표현 가능해야 합니다. 자세한 내용은 Drawbacks 섹션의 확장된 제안을 참조하세요.

자세한 디자인(비 보간 사례)

다음 형식으로 새 string_literal 프로덕션을 추가합니다.

string_literal
    : regular_string_literal
    | verbatim_string_literal
    | raw_string_literal
    ;

raw_string_literal
    : single_line_raw_string_literal
    | multi_line_raw_string_literal
    ;

raw_string_literal_delimiter
    : """
    | """"
    | """""
    | etc.
    ;

raw_content
    : not_new_line+
    ;

single_line_raw_string_literal
    : raw_string_literal_delimiter raw_content raw_string_literal_delimiter
    ;

multi_line_raw_string_literal
    : raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

not_new_line
    : <any unicode character that is not new_line>
    ;

raw_string_literal 끝 구분 기호는 시작 구분 기호와 일치해야 합니다. 따라서 시작 구분 기호가 """"" 경우 끝 구분 기호도 해당 구분 기호여야 합니다.

raw_string_literal 대한 위의 문법은 다음과 같이 해석되어야 합니다.

  1. 그것은 적어도 세 개의 따옴표로 시작됩니다 (하지만 따옴표 개수에 상한은 없습니다).
  2. 그런 다음 시작 따옴표와 동일한 줄의 내용으로 계속 진행합니다. 같은 줄에 있는 이러한 콘텐츠는 비어 있거나 비어있지 않을 수 있습니다. 'blank'는 '완전히 공백'과 동의어입니다.
  3. 동일한 줄의 내용이 비어 있지 않은 경우 더 이상 콘텐츠를 따를 수 없습니다. 즉, 리터럴은 동일한 줄에 동일한 수의 따옴표로 끝나야 합니다.
  4. 같은 줄의 내용이 비어 있으면, 리터럴은 new_line와 함께 몇 개의 후속 콘텐츠 줄과 new_line로 계속될 수 있습니다.
    • 콘텐츠 줄은 new_line제외한 모든 텍스트입니다.
    • 그런 다음 new_linewhitespace 약간의 숫자(0이 될 수도 있음)와 리터럴이 시작한 것과 동일한 수의 따옴표로 끝납니다.

원시 문자열 리터럴 값

시작과 끝 raw_string_literal_delimiter 사이의 부분은 다음과 같은 방식으로 raw_string_literal 값을 형성하는 데 사용됩니다.

  • single_line_raw_string_literal의 경우 리터럴 값은 정확히 시작과 끝 raw_string_literal_delimiter사이의 내용이 됩니다.
  • multi_line_raw_string_literal 경우 초기 whitespace* new_line 마지막 new_line whitespace* 문자열 값의 일부가 아닙니다. 그러나 whitespace* 터미널 앞의 마지막 raw_string_literal_delimiter 부분은 '들여쓰기 공백'으로 간주되며 다른 줄이 해석되는 방식에 영향을 미칩니다.
  • 최종 값을 얻으려면 (raw_content | new_line)* 시퀀스를 탐색하고 다음을 수행합니다.
    • new_line 경우 new_line 내용이 최종 문자열 값에 추가됩니다.
    • 'blank' raw_content가 아닌 경우(not_new_line+whitespace 문자가 아닌 다른 문자가 포함되어 있는 경우)
      • 'raw_content의 접두사는 '들여쓰기 공백'이어야 합니다.' 그렇지 않으면 오류입니다.
      • '들여쓰기 공백'은 raw_content 시작 부분에서 제거되고 나머지는 최종 문자열 값에 추가됩니다.
    • '공백' raw_content인 경우에(즉, not_new_line+이 완전히 whitespace일 때):
      • '들여쓰기 공백'은 raw_content의 접두어이거나 raw_content이 '들여쓰기 공백'의 접두어여야 합니다. 그렇지 않으면 오류입니다.
      • '들여쓰기 공백'의 대부분은 raw_content 시작 부분에서 제거되며, 남은 공백은 최종 문자열 값에 추가됩니다.

해명:

  1. single_line_raw_string_literalnew_line 값을 포함한 문자열을 나타낼 수 없습니다. single_line_raw_string_literal는 '들여쓰기 공백' 트리밍 작업에 참여하지 않습니다. 해당 값은 항상 시작과 끝 구분 기호 사이의 정확한 문자입니다.

  2. 마지막 콘텐츠 줄의 마지막 multi_line_raw_string_literalnew_line이 무시하기 때문에, 시작 new_line와 종료 new_line이 없는 문자열을 나타냅니다.

var v1 = """
         This is the entire content of the string.
         """;

시작 new_line를 무시하는 방식과의 대칭을 유지하며, '들여쓰기 공백'을 항상 조정할 수 있는 일관된 방법을 제공합니다. 터미널 new_line 문자열을 나타내려면 다음과 같이 추가 줄을 제공해야 합니다.

var v1 = """
         This string ends with a new line.

         """;
  1. single_line_raw_string_literal은 따옴표(")로 시작하거나 끝나는 문자열 값을 나타낼 수 없지만, 이를 지원할 수 있는 방법에 대한 확장은 Drawbacks 섹션에서 제시되어 있습니다.

  2. multi_line_raw_string_literal은 초기 whitespace* new_line에 이어 raw_string_literal_delimiter로 시작합니다. 구분 기호 뒤의 이 콘텐츠는 완전히 무시되며 문자열 값을 결정할 때 어떤 방식으로도 사용되지 않습니다. 이렇게 하면 메커니즘에서 콘텐츠가 raw_string_literal 문자 자체로 시작하는 " 지정할 수 있습니다. 예를 들어:

var v1 = """
         "The content of this string starts with a quote
         """;
  1. raw_string_literal 따옴표(")로 끝나는 콘텐츠를 나타낼 수도 있습니다. 종결 구분 기호는 자체 줄에 있어야 하기 때문에 지원됩니다. 예를 들어:
var v1 = """
         "The content of this string starts and ends with a quote"
         """;
var v1 = """
         ""The content of this string starts and ends with two quotes""
         """;
  1. '비어있는 것' raw_content이 '들여쓰기 공백'의 접두사이거나 '들여쓰기 공백'이 그것의 접두사가 되어야 한다는 요구 사항은 혼합된 공백으로 인한 혼란스러운 시나리오가 발생하지 않도록 도움을 줍니다. 특히, 해당 줄에서 무엇이 일어나야 할지가 불분명할 수 있기 때문입니다. 예를 들어 다음 경우는 불법입니다.
var v1 = """
         Start
<tab>
         End
         """;
  1. 여기서 '들여쓰기 공백'은 9개의 공백 문자이지만, 'blank' raw_content는 그것으로 시작하는 접두사가 아닙니다. <tab> 줄을 어떻게 처리해야 하는지에 대한 명확한 대답은 없습니다. 무시해야 하나요? .........<tab>와 동일해야 하나요? 따라서, 불법을 만드는 것은 혼란을 피하기위한 가장 명확한 것 같다.

  2. 하지만 다음 사례는 합법적이며 동일한 문자열을 나타냅니다.

var v1 = """
         Start
<four spaces>
         End
         """;
var v1 = """
         Start
<nine spaces>
         End
         """;

두 경우 모두 '들여쓰기 공백'은 9칸의 공백으로 이루어집니다. 그리고 두 경우 모두 가능한 한 많은 접두사를 제거하여 각 경우의 '빈' raw_content 비어 있게 만듭니다(모든 new_line계산하지 않음). 이렇게 하면 사용자가 이러한 줄을 복사/붙여넣거나 편집할 때 이러한 줄의 공백을 보고 걱정할 필요가 없습니다.

  1. 의 경우:
var v1 = """
         Start
<ten spaces>
         End
         """;

'들여쓰기 공백'은 여전히 9개의 공백입니다. 하지만 여기서는 가능한 한 많은 '들여쓰기 공백'을 제거하고 '공백' raw_content이 최종 콘텐츠에 단일 공백으로 기여하도록 할 것입니다. 이렇게 하면 콘텐츠에 보존해야 하는 이러한 줄에 공백이 필요한 경우가 허용됩니다.

  1. 다음은 기술적으로 합법적이지 않습니다.
var v1 = """
         """;

원시 문자열의 시작 부분에는 new_line 있어야 하지만 끝에는 new_line 있어야 하기 때문입니다(그렇지 않음). 최소한의 법적 raw_string_literal는 다음과 같습니다.

var v1 = """

         """;

그러나 이 문자열은 ""과 동일하여 확실히 흥미롭지 않습니다.

들여쓰기 예제

'들여쓰기 공백' 알고리즘은 여러 입력에 대해 다음과 같이 시각화할 수 있습니다. 다음 예제에서는 세로 막대 문자 | 사용하여 결과 원시 문자열의 첫 번째 열을 보여 줍니다.

예제 1 - 표준 사례

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

다음과 같이 해석됩니다.

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |</element>
           """;

예제 2 - 콘텐츠와 동일한 줄에서 구분 기호를 종료합니다.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>""";

이것은 불법입니다. 마지막 콘텐츠 줄은 new_line으로 종료해야 합니다.

예제 3 - 시작 구분 기호 전에 종료 구분 기호

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

다음과 같이 해석됩니다.

var xml = """
|          <element attr="content">
|            <body>
|            </body>
|          </element>
""";

예제 4 - 시작 구분 기호 후 종료 구분 기호

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
              """;

이것은 불법입니다. 콘텐츠 줄은 '들여쓰기 공백'으로 시작해야 합니다.

예제 5 - 빈 줄

var xml = """
          <element attr="content">
            <body>
            </body>

          </element>
          """;

다음과 같이 해석됩니다.

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

예제 6 - 접두사보다 공백이 적은 빈 선(점이 공백을 나타낸다)

var xml = """
          <element attr="content">
            <body>
            </body>
....
          </element>
          """;

다음과 같이 해석됩니다.

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

예제 7 - 접두사보다 공백이 많은 빈 줄(점이 공백을 나타낸다)

var xml = """
          <element attr="content">
            <body>
            </body>
..............
          </element>
          """;

다음과 같이 해석됩니다.

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |....
          |</element>
           """;

디자인 세부 사항(인터폴레이션 사례)

일반 보간 문자열(예: $"...")의 보간은 { 문자를 사용하여 interpolation 시작하고 {{ 이스케이프 시퀀스를 사용하여 실제 열린 중괄호 문자를 삽입하여 지원됩니다. 이 동일한 메커니즘을 사용하면 이 제안의 목표 '1'과 '2'를 위반할 수 있습니다. 핵심 문자로 {을 갖는 언어들(예: JavaScript, JSON, Regex, 및 포함형 C#)에 대해 이제 원시 문자열 리터럴의 목적에 반하는 이스케이프가 필요하게 됩니다.

보간을 지원하기 위해 일반적인 $" 보간된 문자열과는 다른 방식으로 도입합니다. 특히 interpolated_raw_string_literal는 일정량의 $ 문자로 시작됩니다. 이러한 개수는 {구분하기 위해 리터럴 내용에 필요한 }(및 interpolation) 문자 수를 나타냅니다. 중요한 것은 중괄호에 대한 회피 메커니즘이 여전히 존재하지 않는다는 점입니다. 대신 따옴표(")와 마찬가지로 리터럴 자체는 항상 문자열의 나머지 내용과 충돌하지 않는 보간을 위한 구분 기호를 지정할 수 있습니다. 예를 들어 보간 구멍이 포함된 JSON 리터럴은 다음과 같이 작성할 수 있습니다.

var v1 = $$"""
         {
            "orders": 
            [
                { "number": {{order_number}} }
            ]
         }
         """

이는 {{...}}$$ 구분 기호 접두사로 지정된 두 개의 중괄호의 필수 개수와 일치함을 나타냅니다. 단일 $의 경우, 보간은 일반 보간 문자열 리터럴에서와 같이 {...}로 지정됩니다. 즉, N$ 문자가 포함된 보간된 리터럴에는 동일한 종류의 2*N-1 중괄호가 연속으로 올 수 있습니다. 마지막에 있는 N 중괄호는 보간을 시작하거나 종료하고, 나머지 N-1 중괄호는 단순히 내용으로 취급됩니다. 예를 들어:

var v1 = $$"""X{{{1+1}}}Z""";

이 경우, 내부의 두 {{}} 중괄호는 보간에 속하며, 외부의 단일 중괄호는 단순히 내용일 뿐입니다. 따라서 위의 문자열은 콘텐츠 X{2}Z와 동일합니다. 2*N(또는 그 이상) 중괄호를 갖는 것은 항상 오류입니다. 콘텐츠의 중괄호 시퀀스를 길게 하려면 $ 문자의 수를 그에 맞게 늘려야 합니다.

보간된 원시 문자열 리터럴은 다음과 같이 정의됩니다.

interpolated_raw_string_literal
    : single_line_interpolated_raw_string_literal
    | multi_line_interpolated_raw_string_literal
    ;

interpolated_raw_string_start
    : $
    | $$
    | $$$
    | etc.
    ;

interpolated_raw_string_literal_delimiter
    : interpolated_raw_string_start raw_string_literal_delimiter
    ;

single_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter
    ;

multi_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

interpolated_raw_content
    : (not_new_line | raw_interpolation)+
    ;

raw_interpolation
    : raw_interpolation_start interpolation raw_interpolation_end
    ;

raw_interpolation_start
    : {
    | {{
    | {{{
    | etc.
    ;

raw_interpolation_end
    : }
    | }}
    | }}}
    | etc.
    ;

위의 내용은 raw_string_literal 정의와 비슷하지만 몇 가지 중요한 차이점이 있습니다. interpolated_raw_string_literal 다음과 같이 해석되어야 합니다.

  1. 그것은 하나 이상의 달러 기호(상한은 없음)로 시작하며 그 다음에는 세 개의 따옴표(상한은 없음)가 온다.
  2. 그런 다음 시작 따옴표와 동일한 줄의 콘텐츠를 계속합니다. 같은 줄에 있는 이 콘텐츠는 비어 있거나 비어 있지 않을 수 있습니다. 'blank'는 '완전히 공백'과 동의어입니다.
  3. 동일한 줄의 콘텐츠가 비어 있지 않은 경우 추가 콘텐츠가 뒤따를 수 없습니다. 즉, 리터럴은 동일한 줄에 동일한 수의 따옴표로 끝나야 합니다.
  4. 같은 줄의 내용이 비어 있으면, 리터럴은 new_line와 함께 몇 개의 후속 콘텐츠 줄과 new_line로 계속될 수 있습니다.
    • 콘텐츠 줄은 new_line제외한 모든 텍스트입니다.
    • 콘텐츠 한 줄에는 어느 위치에서든 여러 번의 raw_interpolation이 포함될 수 있습니다. raw_interpolation 리터럴 시작 시 달러 기호 수와 같은 개수의 열린 중괄호({)로 시작해야 합니다.
    • '들여쓰기 공백'이 비어 있지 않으면 raw_interpolationnew_line의 뒤에 즉시 올 수 없습니다.
    • raw_interpolation§12.8.3에 지정된 일반 규칙을 따릅니다. 모든 raw_interpolation은 달러 기호와 열린 중괄호의 총 개수와 동일한 수의 닫힌 중괄호(})로 끝나야 합니다.
    • 어떤 interpolation든지 일반 interpolation(verbatim_string_literal) 내의 @""과 동일한 방식으로 자체적으로 새 줄을 포함할 수 있습니다.
    • 그런 다음 new_linewhitespace 약간의 숫자(0이 될 수도 있음)와 리터럴이 시작한 것과 동일한 수의 따옴표로 끝납니다.

보간 문자열 값 계산은 일반 raw_string_literal과 동일한 규칙을 따르며, 단 raw_interpolation이 포함된 줄을 처리할 수 있도록 업데이트되었습니다. 문자열 값 빌드는 보간 구멍이 런타임 시 해당 식이 생성하는 값으로 대체되는 것과 같은 방식으로 수행됩니다. interpolated_raw_string_literalFormattableString로 변환되는 경우, 보간 값은 해당 순서대로 arguments 배열에 FormattableString.Create로 전달됩니다. 의 '들여쓰기 공백'이 모든 줄에서 제거된 후, 의 나머지 내용은 에 전달될 문자열을 생성하는 데 사용됩니다. 이때 이 발생한 각 위치에는 적절하게 번호가 매겨진 내용이 포함됩니다(또는 형식인 경우 이 포함됩니다).

위의 사양에는 모호성이 있습니다. 특히 텍스트에서 {의 섹션과 {의 보간이 인접할 때입니다. 예를 들어:

var v1 = $$"""
         {{{order_number}}}
         """

이것은 {{ {order_number } }} 또는 { {{order_number}} }로 해석될 수 있습니다. 그러나 전자가 불법이므로(C# 식이 {시작할 수 없음) 그런 식으로 해석하는 것은 무의미합니다. 그래서 가장 안쪽의 { 중괄호와 } 중괄호가 보간을 형성하고, 가장 바깥쪽 중괄호가 텍스트를 형성하는 후자의 방식으로 해석합니다. 미래에 언어가 중괄호로 둘러싸인 표현을 지원하면 문제가 될 수 있습니다. 그러나 이 경우 다음과 같은 경우를 작성하는 것이 좋습니다. {{({some_new_expression_form})}}. 여기서 괄호는 리터럴/보간의 나머지 부분에서 식 부분을 지정하는 데 도움이 됩니다. 이는 보간(예: {(x ? y : z)})의 서식/맞춤 지정자와 충돌하지 않도록 3항 조건식을 래핑해야 하는 방식과 이미 우선적으로 적용됩니다.

단점

원시 문자열 리터럴은 언어에 복잡성을 더합니다. 이미 우리는 여러 가지 용도로 많은 문자열 리터럴 형식을 가지고 있습니다. "" 문자열, @"" 문자열 및 $"" 문자열에는 이미 많은 성능과 유연성이 있습니다. 그러나 그들은 모두 이스케이프 할 필요가 없는 원시 콘텐츠를 제공 할 수있는 방법이 부족합니다.

위의 규칙은 4.a경우를 지원하지 않습니다.

  1. ...
    • 필요하다면, 복잡성을 추가하여 다음과 같이 명확히 할 수 있습니다: new_line을 포함하지 않는 모든 문자열에 대해, 시작하거나 끝에 따옴표 " 문자를 포함할 수 있지만, 문자열 리터럴 자체를 한 줄로 표현 가능해야 합니다.

시작 또는 끝 따옴표(")가 구분 기호 자체가 아니라 내용에 속해야 한다는 것을 알 수 있는 수단이 없기 때문입니다. 하지만 지원하려는 중요한 시나리오인 경우 병렬 ''' 구문을 추가하여 """ 양식과 함께 사용할 수 있습니다. 이 병렬 구문을 사용하여 "로 시작하고 끝나는 단일 줄 문자열을 병렬 구문 '''"This string starts and ends with quotes"'''와 함께 """'This string starts and ends with apostrophes'"""로 쉽게 작성할 수 있습니다. 또한 따옴표 문자를 시각적으로 구분할 수 있도록 지원하는 것이 바람직할 수 있습니다. 이는 기본적으로 하나의 따옴표 문자를 다른 것보다 훨씬 더 많이 사용하는 언어를 포함할 때 도움이 될 수 있습니다.

대안

https://github.com/dotnet/csharplang/discussions/89 여기에 많은 옵션을 다룹니다. 대안은 많지만, 너무 복잡하고 인체 공학적으로 불편한 느낌이 듭니다. 이 방법은 문자열 내용과 충돌할 염려가 없을 때까지 시작/끝 따옴표 길이를 계속 늘리는 단순성을 선택합니다. 또한 작성하는 코드가 잘 들여쓰기된 상태를 유지하면서도, 대부분의 코드에서 원하는 비들여쓰기된 리터럴을 생성할 수 있습니다.

하지만 가장 흥미로운 잠재적 변형 중 하나는 이러한 원시 문자열 리터럴에 `(또는 ```) 펜스를 사용하는 것입니다. 다음과 같은 몇 가지 이점이 있습니다.

  1. 문자열이 따옴표로 시작하거나 끝나는 모든 문제를 방지할 수 있습니다.
  2. 그것은 마크다운과 유사한 모습일 것입니다. 사용자가 markdown 해석을 기대할 수 있으므로 그 자체로는 좋지 않을 수 있습니다.
  3. 원시 문자열 리터럴은 대부분의 경우 단일 문자로 시작하고 끝나야 하며, 백틱 자체를 포함하는 훨씬 드문 콘텐츠의 경우 여러 문자만 필요합니다.
  4. 마치 마크다운처럼 ```xml을 미래에 확장하는 것이 자연스러울 것 같다. 물론 그렇지만, 그것은 또한 """ 형태에 해당한다.

전반적으로, 여기에 순 이익은 작은 것 같다. C#의 역사에 따라, 저는 "string literal의 구분 기호로 계속 사용되어야 한다고 생각합니다. 이는 @""$""에서도 마찬가지입니다.

디자인 회의

논의할 미해결 문제 해결된 문제:

  • [x] 한 줄 양식을 사용해야 하나요? 우리는 기술적으로 그것없이 할 수 있습니다. 그러나 줄임표가 포함되지 않은 단순 문자열에는 항상 3줄 이상이 소요됩니다. 나는 탈출을 피하기 위해 단일 라인 구문을 세 줄로 강제하는 것이 너무 부담스럽다고 생각합니다.

디자인 결정: 예, 단일 줄 형식을 사용하겠습니다.

  • [x] 여러 줄 시작해야 하나요? 저는 우리가 해야 한다고 생각합니다. 그것은 또한 우리에게 미래에 """xml 같은 것들을 지원할 수있는 능력을 제공합니다.

디자인 결정: 예, 여러 줄은 반드시 새 줄로 시작해야 합니다.

  • [x] 자동 서식 해제를 해야 하나요? 저는 우리가 해야 한다고 생각합니다. 코드를 훨씬 더 즐겁게 보이게 합니다.

디자인 결정: 예, 자동 내어쓰기가 진행됩니다.

  • [x] 공백 유형을 혼합하지 못하도록 일반 공백 사용을 제한해야 하나요? 나는 우리가해야한다고 생각하지 않습니다. 실제로 "들여쓰기 위한 탭, 맞춤을 위한 공백"이라는 일반적으로 사용되는 전략이 있습니다. 시작 구분 기호가 탭 스톱에서 시작되지 않는 경우, 끝 구분 기호를 시작 구분 기호에 맞추는 데 이것을 사용하는 것이 매우 자연스럽습니다.

디자인 결정: 공백 혼합에 대한 제한은 없습니다.

  • [x] 울타리에 다른 것을 사용해야 하나요? ` markdown 구문과 일치하며 항상 세 개의 따옴표로 이러한 문자열을 시작할 필요가 없다는 것을 의미합니다. 단지 하나는 일반적인 경우에 충분 할 것이다.

디자인 결정: """ 사용합니다.

  • [x] 구분 기호에 문자열 값에서 가장 긴 따옴표 시퀀스보다 더 많은 따옴표가 있어야 하나요? 기술적으로는 필요하지 않습니다. 예를 들어:
var v = """
        contents"""""
        """

이 문자열은 """을 구분 기호로 사용합니다. 몇몇 커뮤니티 구성원은 이것이 혼란스럽다고 말했고, 이와 같은 경우 구분 기호에는 항상 더 많은 문자가 있어야 합니다. 그러면 다음과 같습니다.

var v = """"""
        contents"""""
        """"""

디자인 결정: 예, 구분 기호는 문자열 자체의 따옴표 시퀀스보다 길어야 합니다.