Littéral de chaîne brute
Remarque
Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.
Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .
Résumé
Il commence par un minimum de trois caractères """
(sans maximum), le contenu de la chaîne (qui ne peut contenir aucun caractère new_line
), et se termine ensuite par le même nombre de guillemets avec lesquels le littéral a commencé. Par exemple:
var xml = """
<element attr="content"/>
""";
Étant donné que le contenu imbriqué peut lui-même vouloir utiliser """
les délimiteurs de début/fin peuvent être plus longs comme suit :
var xml = """"
Ok to use """ here
"""";
Pour faciliter la lecture du texte et autoriser la mise en retrait que les développeurs aiment dans le code, ces littéraux de chaîne suppriment naturellement la mise en retrait spécifiée sur la dernière ligne lors de la production de la valeur littérale finale. Par exemple, un littéral de la forme :
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Contiendra :
<element attr="content">
<body>
</body>
</element>
Cela permet au code d’avoir l’apparence naturelle, tout en produisant des littéraux souhaités et en évitant les coûts d’exécution si cela nécessite l’utilisation de routines de manipulation de chaînes spécialisées.
Si le comportement de mise en retrait n’est pas souhaité, il est également facile de le désactiver comme suit :
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Un formulaire à une seule ligne est également pris en charge. Il commence par un minimum de trois caractères """
(sans maximum), le contenu de la chaîne (qui ne peut contenir aucun caractère new_line
), et se termine ensuite par le même nombre de guillemets avec lesquels le littéral a commencé. Par exemple:
var xml = """<summary><element attr="content"/></summary>""";
Les chaînes brutes interpolées sont également prises en charge. Dans ce cas, la chaîne spécifie le nombre d’accolades nécessaires pour démarrer une interpolation (déterminé par le nombre de signes dollar présents au début du littéral). Toute séquence d’accolades avec moins d’accolades que cela est simplement traitée comme du contenu. Par exemple:
var json = $$"""
{
"summary": "text",
"length" : {{value.Length}},
};
""";
Motivation
C# ne dispose pas d’un moyen général de créer des littéraux de chaîne simples qui peuvent contenir efficacement n’importe quel texte arbitraire. Toutes les formes de littéraux de chaînes C# aujourd’hui nécessitent une forme d’échappement au cas où le contenu utiliserait un caractère spécial (toujours si un délimiteur est utilisé). Cela empêche d’avoir facilement des littéraux contenant d’autres langages (par exemple, un littéral XML, HTML ou JSON).
Toutes les approches actuelles pour former ces littéraux en C# aujourd’hui obligent toujours l’utilisateur à échapper manuellement le contenu. Modifier à ce stade peut être très ennuyeux car l’échappement ne peut être évité et doit être traité chaque fois qu’il apparaît dans le contenu. C’est particulièrement pénible pour les regex, surtout lorsqu’elles contiennent des guillemets ou des barres obliques inverses. Même avec une chaîne verbatim (@""
), les guillemets eux-mêmes doivent être échappés, ce qui conduit à un mélange de C# et de regex entremêlés. {
et }
sont de même frustrants dans les chaînes interpolées ($""
).
Le nœud du problème est que toutes nos chaînes ont un délimiteur de début/fin fixe. Tant que cela est le cas, nous devrons toujours avoir un mécanisme d’échappement car le contenu de la chaîne peut avoir besoin de spécifier ce délimiteur de fin dans leur contenu. Cela est particulièrement problématique car ce délimiteur "
est extrêmement courant dans de nombreuses langues.
Pour résoudre ce problème, cette proposition permet des délimiteurs de début et de fin flexibles afin qu’ils puissent toujours être effectués de manière à ne pas entrer en conflit avec le contenu de la chaîne.
Objectifs
- Fournir un mécanisme qui permettra à toutes les valeurs de chaîne d’être fournies par l’utilisateur sans besoin de aucune séquence d’échappement. Étant donné que toutes les chaînes doivent être représentées sans séquences d’échappement, il doit toujours être possible pour l’utilisateur de spécifier des délimiteurs qui seront garantis de ne pas entrer en collision avec tout contenu de texte.
- Supporter les interpolations de la même manière. Comme ci-dessus, étant donné que toutes les chaînes doivent être représentées sans échappement, il doit toujours être possible pour l’utilisateur de spécifier un délimiteur
interpolation
qui sera garanti de ne pas entrer en collision avec tout contenu de texte. Il est important de noter que les langues qui utilisent nos caractères délimiteurs d'interpolation ({
et}
) devraient offrir une expérience de première classe et ne pas être pénibles à utiliser. - Les littéraux de chaînes multiligne devraient être agréables dans le code et ne pas rendre l’indentation au sein de l’unité de compilation étrange. Il est important de noter que les valeurs littérales qui elles-mêmes n'ont pas de retrait ne doivent pas être forcées d'occuper la première colonne du fichier, car cela peut perturber le flux du code et les rendrait mal alignées par rapport au reste du code qui les entoure.
- Ce comportement devrait être facile à remplacer tout en gardant les littéraux clairs et faciles à lire.
- Pour toutes les chaînes qui ne contiennent pas le caractère
new_line
et ne commencent ni ne se terminent par un guillemet ("
), il devrait être possible de représenter la chaîne littérale elle-même sur une seule ligne.- Optionnellement, avec une complexité supplémentaire, nous pourrions affiner cela pour déclarer que : Pour toutes les chaînes qui ne contiennent pas elles-mêmes de
new_line
(mais peuvent commencer ou se terminer par un caractère guillemet"
), il devrait être possible de représenter le littéral de chaîne lui-même sur une seule ligne. Pour plus d’informations, consultez la proposition développée dans la sectionDrawbacks
.
- Optionnellement, avec une complexité supplémentaire, nous pourrions affiner cela pour déclarer que : Pour toutes les chaînes qui ne contiennent pas elles-mêmes de
Conception détaillée (cas de non-interpolation)
Nous ajouterons une nouvelle string_literal
production sous la forme suivante :
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>
;
Le délimiteur de fin à un raw_string_literal
doit correspondre au délimiteur de départ. Par conséquent, si le délimiteur de départ est """""
le délimiteur de fin doit également être celui-ci.
La grammaire ci-dessus pour un raw_string_literal
doit être interprétée comme suit :
- Il commence par au moins trois guillemets (mais aucune limite supérieure sur les guillemets).
- Il continue ensuite avec le contenu sur la même ligne que les guillemets de début. Ces contenus sur la même ligne peuvent être vides ou non vides. 'blank' est synonyme de 'entièrement blanc'.
- Si le contenu de cette même ligne n’est pas vide, aucun autre contenu ne peut suivre. En d’autres termes, le littéral doit se terminer par le même nombre de guillemets sur cette même ligne.
- Si le contenu sur la même ligne est vide, alors le littéral peut continuer avec un
new_line
et un certain nombre de lignes de contenu subséquentes etnew_line
s.- Une ligne de contenu est n’importe quel texte à l’exception d’un
new_line
. - Il se termine ensuite par un
new_line
, un certain nombre (éventuellement zéro) dewhitespace
et le même nombre de guillemets avec lesquels le littéral a commencé.
- Une ligne de contenu est n’importe quel texte à l’exception d’un
Valeur du littéral de chaîne brute
Les parties entre les raw_string_literal_delimiter
de début et de fin sont utilisées pour former la valeur du raw_string_literal
de la manière suivante :
- Dans le cas de
single_line_raw_string_literal
, la valeur du littéral sera exactement le contenu entre leraw_string_literal_delimiter
de début et de fin. - Dans le cas de
multi_line_raw_string_literal
lawhitespace* new_line
initiale et lanew_line whitespace*
finale ne fait pas partie de la valeur de la chaîne. Cependant, la portionwhitespace*
finale précédant le terminalraw_string_literal_delimiter
est considérée comme l’« espace d’indentation » et affectera la façon dont les autres lignes sont interprétées. - Pour obtenir la valeur finale, la séquence de
(raw_content | new_line)*
est parcourue et les opérations suivantes sont effectuées :- Si c’est un
new_line
, le contenu dunew_line
est ajouté à la valeur finale de la chaîne. - S’il ne s’agit pas d’un
raw_content
vide (c’est-à-direnot_new_line+
contient un caractère nonwhitespace
) :- L’« espace d’indentation » doit être un préfixe de
raw_content
. Il s’agit d’une erreur dans le cas contraire. - L’« espace d’indentation » est supprimé du début de
raw_content
et le reste est ajouté à la valeur finale de la chaîne.
- L’« espace d’indentation » doit être un préfixe de
- S’il s’agit d’un
raw_content
vide (c’est-à-dire quenot_new_line+
est entièrementwhitespace
) :- L’« espace d’indentation » doit être un préfixe de
raw_content
ou leraw_content
doit être un préfixe de l’« espace d’indentation ». Il s’agit d’une erreur dans le cas contraire. - Autant de l’« espace d’indentation » est supprimé du début de
raw_content
et tout reste est ajouté à la valeur finale de la chaîne.
- L’« espace d’indentation » doit être un préfixe de
- Si c’est un
Clarifications :
Un
single_line_raw_string_literal
n’est pas capable de représenter une chaîne avec une valeurnew_line
dans celle-ci. Unsingle_line_raw_string_literal
ne participe pas à la suppression de l’« espace d’indentation ». Sa valeur correspond toujours exactement aux caractères situés entre les délimiteurs de début et de fin.Étant donné qu'un
multi_line_raw_string_literal
ignore lenew_line
final de la dernière ligne de contenu, la chaîne suivante est une chaîne sansnew_line
de départ et sansnew_line
de fin.
var v1 = """
This is the entire content of the string.
""";
Cela maintient la symétrie avec la façon dont le new_line
de début est ignoré, et cela fournit également un moyen uniforme de garantir que l’« espace d’indentation » peut toujours être ajusté. Pour représenter une chaîne avec un terminal new_line
une ligne supplémentaire doit être fournie comme suit :
var v1 = """
This string ends with a new line.
""";
Une
single_line_raw_string_literal
ne peut pas représenter une valeur de chaîne qui commence ou se termine par un guillemet ("
) bien qu’une augmentation de cette proposition soit fournie dans la sectionDrawbacks
qui montre comment cela peut être pris en charge.Un
multi_line_raw_string_literal
commence parwhitespace* new_line
suivant laraw_string_literal_delimiter
initiale. Le contenu après le délimiteur est entièrement ignoré et n'est pas utilisé de quelque manière dans la détermination de la valeur de la chaîne. Cela permet à un mécanisme de spécifier unraw_string_literal
dont le contenu commence par un caractère"
lui-même. Par exemple:
var v1 = """
"The content of this string starts with a quote
""";
- Un
raw_string_literal
peut également représenter du contenu qui se termine par un guillemet ("
). Cela est supporté car le délimiteur de terminaison doit être sur sa propre ligne. Par exemple:
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""
""";
- L’exigence qu’un
raw_content
« vide » soit soit un préfixe de l’« espace d’indentation », soit que l’« espace d’indentation » soit un préfixe de celui-ci aide à garantir que des scénarios confus avec un mélange de types d’espaces ne se produisent pas, surtout qu’il serait alors peu clair ce qu’il devrait arriver avec cette ligne. Par exemple, le cas suivant est illégal :
var v1 = """
Start
<tab>
End
""";
Ici, l’« espace d’indentation » est de neuf espaces, mais le
raw_content
« vide » ne commence pas par un préfixe de cela. Il n’y a pas de réponse claire quant à la façon dont cette ligne<tab>
devrait être traitée. Faut-il l’ignorer ? Doit-il être identique à.........<tab>
? Par conséquent, rendre cela illégal semble être le moyen le plus clair pour éviter toute confusion.Les cas suivants sont légaux et représentent la même chaîne :
var v1 = """
Start
<four spaces>
End
""";
var v1 = """
Start
<nine spaces>
End
""";
Dans les deux cas, l’« espace d’indentation » sera de neuf espaces. Et dans les deux cas, nous supprimerons autant de ce préfixe que possible, ce qui conduit le raw_content
« vide » dans chaque cas à être vide (sans compter chaque new_line
). Cela permet aux utilisateurs de ne pas avoir à voir et potentiellement s’inquiéter de l’espace blanc sur ces lignes lorsqu’ils copient/collent ou modifient ces lignes.
- Dans le cas toutefois de :
var v1 = """
Start
<ten spaces>
End
""";
L’« espace d’indentation » sera toujours de neuf espaces. Toutefois, nous allons supprimer autant d'espaces blancs d'indentation que possible, et le raw_content
« vide » ajoutera un seul espace au contenu final. Cela permet les cas où le contenu a besoin d’espaces sur ces lignes qui doivent être préservés.
- Les éléments suivants ne sont techniquement pas juridiques :
var v1 = """
""";
Cela est dû au fait que le début de la chaîne brute doit avoir une new_line
(qu’elle fait) mais que la fin doit également avoir un new_line
(ce qui n’est pas le cas). Le raw_string_literal
légal minimal est :
var v1 = """
""";
Cependant, cette chaîne est décidément inintéressante car elle équivaut à ""
.
Exemples d’indentation
L’algorithme de l’« espace d’indentation » peut être visualisé sur plusieurs entrées comme suit. Les exemples suivants utilisent le caractère de barre verticale |
pour illustrer la première colonne de la chaîne brute résultante :
Exemple 1 - Cas standard
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
est interprété comme
var xml = """
|<element attr="content">
| <body>
| </body>
|</element>
""";
Exemple 2 : Délimiteur de fin sur la même ligne que le contenu.
var xml = """
<element attr="content">
<body>
</body>
</element>""";
C’est illégal. La dernière ligne de contenu doit se terminer par un new_line
.
Exemple 3 - Délimiteur de fin avant le délimiteur de début
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
est interprété comme
var xml = """
| <element attr="content">
| <body>
| </body>
| </element>
""";
Exemple 4 - Délimiteur de fin après le délimiteur de début
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
C’est illégal. Les lignes de contenu doivent commencer par l’« espace d’indentation »
Exemple 5 - Ligne vide
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
est interprété comme
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Exemple 6 - Ligne vide avec moins d’espace blanc que le préfixe (les points représentent des espaces)
var xml = """
<element attr="content">
<body>
</body>
....
</element>
""";
est interprété comme
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Exemple 7 - Ligne vide avec plus d’espace blanc que le préfixe (les points représentent des espaces)
var xml = """
<element attr="content">
<body>
</body>
..............
</element>
""";
est interprété comme
var xml = """
|<element attr="content">
| <body>
| </body>
|....
|</element>
""";
Conception détaillée (cas d’interpolation)
Les interpolations dans les chaînes interpolées normales (par exemple $"..."
) sont supportées aujourd’hui grâce à l’utilisation du caractère {
pour démarrer une interpolation
et l’utilisation d’une séquence d’échappement {{
pour insérer un caractère d’accolade ouvrante réel. L’utilisation de ce même mécanisme violerait les objectifs « 1 » et « 2 » de cette proposition. Les langages qui ont {
comme caractère de base (exemples : JavaScript, JSON, Regex, et même C# intégré) auraient maintenant besoin d’échappement, annulant ainsi le but des littéraux de chaînes brutes.
Pour prendre en charge les interpolations, nous les introduisons d'une manière différente de celle des chaînes interpolées normales $"
. Plus précisément, un interpolated_raw_string_literal
commence par un certain nombre de caractères $
. Le nombre de ces caractères indique le nombre de caractères {
(et }
) nécessaires dans le contenu du littéral pour délimiter le interpolation
. Il est important de noter qu’il n’existe toujours aucun mécanisme d’échappement pour les accolades. Au contraire, tout comme pour les guillemets ("
), le littéral lui-même peut toujours s’assurer qu’il spécifie des délimiteurs pour les interpolations qui ne risquent pas de entrer en collision avec le reste du contenu de la chaîne. Par exemple, un littéral JSON contenant des trous d’interpolation peut être écrit comme suit :
var v1 = $$"""
{
"orders":
[
{ "number": {{order_number}} }
]
}
"""
Ici, le {{...}}
correspond au nombre requis de deux accolades spécifié par le préfixe de délimiteur $$
. Dans le cas d’un seul $
, cela signifie que l’interpolation est spécifiée de la même manière que {...}
dans les littéraux de chaîne interpolés normaux. Il est important de noter que cela signifie qu’un littéral interpolé avec les caractères N
$
peut avoir une séquence d’accolades 2*N-1
(du même type consécutivement). Les dernières accolades N
démarreront (ou termineront) une interpolation, et les accolades N-1
restantes seront simplement du contenu. Par exemple:
var v1 = $$"""X{{{1+1}}}Z""";
Dans ce cas, les deux accolades {{
et }}
internes appartiennent à l’interpolation, et les accolades singulières externes sont simplement du contenu. Ainsi, la chaîne ci-dessus équivaut au contenu X{2}Z
. Avoir 2*N
accolades (ou plus) est toujours une erreur. Pour avoir des séquences plus longues d’accolades comme contenu, le nombre de caractères $
doit être augmenté en conséquence.
Les littéraux de chaîne brute interpolés sont définis comme suit :
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.
;
La définition ci-dessus est similaire à la définition de raw_string_literal
, mais avec quelques différences importantes. Une interpolated_raw_string_literal
doit être interprétée comme suit :
- Il commence par au moins un signe dollar (mais pas de limite supérieure), puis trois guillemets (également sans limite supérieure).
- Il continue ensuite avec le contenu sur la même ligne que les guillemets de début. Ce contenu sur la même ligne peut être vide ou non vide. 'blank' est synonyme de 'entièrement blanc'.
- Si le contenu de cette même ligne n’est pas vide, aucun autre contenu ne peut suivre. En d’autres termes, le littéral doit se terminer par le même nombre de guillemets sur cette même ligne.
- Si le contenu sur la même ligne est vide, alors le littéral peut continuer avec un
new_line
et un certain nombre de lignes de contenu subséquentes etnew_line
s.- Une ligne de contenu est n’importe quel texte à l’exception d’un
new_line
. - Une ligne de contenu peut contenir plusieurs occurrences
raw_interpolation
à n’importe quelle position. Leraw_interpolation
doit commencer avec un nombre égal d’accolades ouvrantes ({
) que le nombre de signes dollar au début du littéral. - Si l’espace blanc de mise en retrait n’est pas vide, un
raw_interpolation
ne peut pas suivre immédiatement unnew_line
. - Le
raw_interpolation
suit les règles normales spécifiées à §12.8.3. Toutraw_interpolation
doit se terminer par le même nombre d’accolades fermantes (}
) que de signes dollar et d’accolades ouvrantes. - Toute
interpolation
peut elle-même contenir de nouvelles lignes de la même manière qu’uneinterpolation
dans uneverbatim_string_literal
normale (@""
). - Il se termine ensuite par un
new_line
, un certain nombre (éventuellement zéro) dewhitespace
et le même nombre de guillemets avec lesquels le littéral a commencé.
- Une ligne de contenu est n’importe quel texte à l’exception d’un
Le calcul de la valeur de chaîne interpolée suit les mêmes règles qu’une raw_string_literal
normale, sauf mise à jour pour gérer les lignes contenant des raw_interpolation
s. La construction de la valeur de la chaîne se fait de la même manière, simplement avec les trous d’interpolation remplacés par les valeurs que ces expressions produisent à l’exécution. Si la interpolated_raw_string_literal
est convertie en FormattableString
, les valeurs des interpolations sont passées dans leur ordre respectif au tableau arguments
à FormattableString.Create
. Le reste du contenu du interpolated_raw_string_literal
après que l’« espace d’indentation » ait été supprimé de toutes les lignes sera utilisé pour générer la chaîne format
passée à FormattableString.Create
, sauf avec des contenus {N}
numérotés de manière appropriée à chaque emplacement où un raw_interpolation
est survenu (ou {N,constant}
dans le cas où son interpolation
est de la forme expression ',' constant_expression
).
Il existe une ambiguïté dans la spécification ci-dessus. Spécifiquement lorsqu’une section de {
dans le texte et {
d’une interpolation se touchent. Par exemple:
var v1 = $$"""
{{{order_number}}}
"""
Cela peut être interprété comme : {{ {order_number } }}
ou { {{order_number}} }
. Toutefois, comme l’ancien est illégal (aucune expression C# ne pourrait commencer par {
) il serait inutile d’interpréter cette façon. Ainsi, nous interprétons de la seconde manière, où les accolades {
et }
les plus internes forment l’interpolation, et les accolades les plus externes forment le texte. À l’avenir, cela pourrait poser un problème si le langage supporte des expressions entourées d’accolades. Toutefois, dans ce cas, la recommandation serait d’écrire un tel cas comme suit : {{({some_new_expression_form})}}
. Ici, les parenthèses aideraient à désigner la portion d’expression du reste du littéral/de l’interpolation. Cette priorité est déjà liée à la façon dont les expressions conditionnelles ternaires doivent être encapsulées pour ne pas entrer en conflit avec le spécificateur de mise en forme/alignement d’une interpolation (par exemple, {(x ? y : z)}
).
Inconvénients
Les littéraux de chaînes brutes ajoutent plus de complexité au langage. Nous avons déjà de nombreuses formes de littéraux de chaînes pour de nombreux usages. Les chaînes ""
, les chaînes @""
et les chaînes $""
sont déjà très puissantes et flexibles. Mais elles n’ont toutes pas de moyen de fournir un contenu brut qui n’a jamais besoin d’échappement.
Les règles ci-dessus ne prennent pas en charge le cas de 4.a:
- ...
- Optionnellement, avec une complexité supplémentaire, nous pourrions affiner cela pour déclarer que : Pour toutes les chaînes qui ne contiennent pas elles-mêmes de
new_line
(mais peuvent commencer ou se terminer par un caractère guillemet"
), il devrait être possible de représenter le littéral de chaîne lui-même sur une seule ligne.
- Optionnellement, avec une complexité supplémentaire, nous pourrions affiner cela pour déclarer que : Pour toutes les chaînes qui ne contiennent pas elles-mêmes de
C’est parce que nous n’avons aucun moyen de savoir qu’une citation de début ou de fin ("
) doit appartenir au contenu et non au délimiteur lui-même. S'il s'agit d'un scénario important que nous voulons prendre en charge, nous pouvons ajouter une construction '''
parallèle pour accompagner la forme """
. Avec cette construction parallèle, une chaîne de ligne unique qui commence et se termine par "
peut être écrite facilement en tant que '''"This string starts and ends with quotes"'''
avec la construction parallèle """'This string starts and ends with apostrophes'"""
. Cela peut également être utile pour aider à séparer visuellement les caractères de guillemets, ce qui peut être bénéfique lors de l’incorporation de langues qui utilisent principalement un caractère de guillemet beaucoup plus que l'autre.
Alternatives
https://github.com/dotnet/csharplang/discussions/89 couvre de nombreuses options ici. Les alternatives sont nombreuses, mais je trouve qu'elles s'égarent trop loin dans la complexité et leur mauvaise ergonomie. Cette approche privilégie la simplicité en augmentant progressivement la longueur des guillemets de début et de fin jusqu’à ce qu’il n’y ait plus de risque de conflit avec le contenu de la chaîne de caractères. Cela permet également au code que vous écrivez d’avoir une bonne indentation, tout en produisant un littéral désindente qui est ce que la plupart du code souhaite.
Une des variations potentielles les plus intéressantes est cependant l’utilisation de délimiteurs `
(ou ```
) pour ces littéraux de chaînes brutes. Cela aurait plusieurs avantages :
- Il éviterait tous les problèmes liés aux chaînes commençant ou se terminant par des guillemets.
- Cela ressemblerait à du markdown. Bien qu’en soi, cela ne soit potentiellement pas une bonne chose, car les utilisateurs pourraient s’attendre à une interprétation Markdown.
- Un littéral de chaîne brute n’aurait qu’à commencer et se terminer par un seul caractère dans la plupart des cas, et ne nécessiterait des multiples que dans le cas beaucoup plus rare de contenus contenant eux-mêmes des back-ticks.
- Il serait naturel d’étendre cela à l’avenir avec
```xml
, à nouveau semblable à Markdown. Bien sûr, c’est aussi vrai de la forme"""
.
Dans l’ensemble cependant, l’avantage net ici semble petit. Conformément à l’histoire C#, je pense que "
devrait continuer à être le délimiteur string literal
, tout comme c’est pour @""
et $""
.
Concevoir des réunions
Problèmes ouverts à discuter Problèmes résolus :
- [x] devrions-nous avoir un formulaire à une seule ligne ? Nous pourrions le faire techniquement sans cela. Mais cela signifierait que les chaînes simples ne contenant pas de nouvelle ligne prenaient toujours au moins trois lignes. Je pense que nous devrions. C’est très lourd de forcer les constructions sur une seule ligne à être sur trois lignes juste pour éviter l’échappement.
Décision de conception : Oui, nous aurons un formulaire de ligne unique.
- [x] devons-nous exiger que les multiligne commencent par une nouvelle ligne ? Je pense que nous devrions. Il nous donne également la possibilité de soutenir des choses comme
"""xml
à l’avenir.
Décision de conception : Oui, nous exigerons que le texte à plusieurs lignes commence sur une nouvelle ligne
- [x] l’auto-désindentation devrait-elle être faite du tout ? Je pense que nous devrions. Cela rend le code beaucoup plus agréable à regarder.
Décision de conception : Oui, la dédentation automatique sera effectuée.
- [x] devons-nous restreindre les espaces blancs communs pour éviter de mélanger les types d’espaces blancs ? Je ne pense pas que nous devrions. En effet, il existe une stratégie d’indentation courante appelée « tabulation pour l’indentation, espace pour l’alignement ». Il serait très naturel d’utiliser cela pour aligner le délimiteur de fin avec le délimiteur de début dans le cas où le délimiteur de début ne commence pas sur un arrêt de tabulation.
Décision de conception : Nous n’aurons aucune restriction sur le mélange d’espaces blancs.
- [x] devrions-nous utiliser quelque chose d’autre pour les clôtures ?
`
correspondrait à la syntaxe markdown et signifierait que nous n’avons pas besoin de toujours démarrer ces chaînes avec trois guillemets. Un seul suffirait pour le cas courant.
Décision de conception : Nous allons utiliser """
- [x] devrions-nous avoir une exigence selon laquelle le délimiteur a plus de guillemets que la séquence de guillemets la plus longue dans la valeur de chaîne ? Techniquement, il n’est pas nécessaire. par exemple:
var v = """
contents"""""
"""
Il s’agit d’une chaîne avec """
comme délimiteur. Plusieurs membres de la communauté ont déclaré que c’est déroutant et nous devrions exiger dans un cas comme celui-ci que le délimiteur ait toujours plus de caractères. Il s’agirait alors de :
var v = """"""
contents"""""
""""""
Décision de conception : Oui, le délimiteur doit être plus long que n’importe quelle séquence de guillemets dans la chaîne elle-même.
C# feature specifications