Runtime: Présentation de System.Rune

Créé le 16 sept. 2017  ·  106Commentaires  ·  Source: dotnet/runtime

Inspiré par la discussion ici:

https://github.com/dotnet/corefxlab/issues/1751

L'un des défis auxquels .NET est confronté avec son support Unicode est qu'il repose sur une conception aujourd'hui obsolète. La façon dont nous représentons les caractères dans .NET est avec System.Char qui est une valeur 16 bits, qui est insuffisante pour représenter les valeurs Unicode.

Les développeurs .NET doivent en savoir plus sur les paires de substitution obscures :

https://msdn.microsoft.com/en-us/library/xcwwfbb8 (v=vs.110).aspx

Les développeurs utilisent rarement ce support, principalement parce qu'ils ne sont pas suffisamment familiarisés avec Unicode, et encore moins avec ce que .NET a à leur offrir.

Je propose que nous introduisions un System.Rune qui est soutenu par un entier 32 bits et qui correspond à un codePoint et que nous affichions en C# le type rune équivalent pour être un alias de ce type.

rune deviendrait le remplacement préféré de char et servirait de base à une bonne gestion de l'Unicode et des chaînes dans .NET.

Quant à savoir pourquoi le nom rune, l'inspiration vient de Go :

https://blog.golang.org/strings

La section "Points de code, caractères et runes" fournit l'explication, une version courte est :

« Point de code » est un peu long, alors Go introduit un terme plus court pour le concept : rune. Le terme apparaît dans les bibliothèques et le code source, et signifie exactement la même chose que "point de code", avec un ajout intéressant.

Mise à jour , j'ai maintenant une implémentation de System.Rune ici :

https://github.com/migueldeicaza/NStack/blob/master/NStack/unicode/Rune.cs

Avec l'API suivante :

public struct Rune {

    public Rune (uint rune);
    public Rune (char ch);

    public static ValueTuple<Rune,int> DecodeLastRune (byte [] buffer, int end);
    public static ValueTuple<Rune,int> DecodeLastRune (NStack.ustring str, int end);
    public static ValueTuple<Rune,int> DecodeRune (byte [] buffer, int start, int n);
    public static ValueTuple<Rune,int> DecodeRune (NStack.ustring str, int start, int n);
    public static int EncodeRune (Rune rune, byte [] dest, int offset);
    public static bool FullRune (byte [] p);
    public static bool FullRune (NStack.ustring str);
    public static int InvalidIndex (byte [] buffer);
    public static int InvalidIndex (NStack.ustring str);
    public static bool IsControl (Rune rune);
    public static bool IsDigit (Rune rune);
    public static bool IsGraphic (Rune rune);
    public static bool IsLetter (Rune rune);
    public static bool IsLower (Rune rune);
    public static bool IsMark (Rune rune);
    public static bool IsNumber (Rune rune);
    public static bool IsPrint (Rune rune);
    public static bool IsPunctuation (Rune rune);
    public static bool IsSpace (Rune rune);
    public static bool IsSymbol (Rune rune);
    public static bool IsTitle (Rune rune);
    public static bool IsUpper (Rune rune);
    public static int RuneCount (byte [] buffer, int offset, int count);
    public static int RuneCount (NStack.ustring str);
    public static int RuneLen (Rune rune);
    public static Rune SimpleFold (Rune rune);
    public static Rune To (Case toCase, Rune rune);
    public static Rune ToLower (Rune rune);
    public static Rune ToTitle (Rune rune);
    public static Rune ToUpper (Rune rune);
    public static bool Valid (byte [] buffer);
    public static bool Valid (NStack.ustring str);
    public static bool ValidRune (Rune rune);
    public override bool Equals (object obj);

    [System.Runtime.ConstrainedExecution.ReliabilityContractAttribute((System.Runtime.ConstrainedExecution.Consistency)3, (System.Runtime.ConstrainedExecution.Cer)2)]
    protected virtual void Finalize ();
    public override int GetHashCode ();
    public Type GetType ();
    protected object MemberwiseClone ();
    public override string ToString ();

    public static implicit operator uint (Rune rune);
    public static implicit operator Rune (char ch);
    public static implicit operator Rune (uint value);

    public bool IsValid {
        get;
    }

    public static Rune Error;
    public static Rune MaxRune;
    public const byte RuneSelf = 128;
    public static Rune ReplacementChar;
    public const int Utf8Max = 4;

    public enum Case {
        Upper,
        Lower,
        Title
    }
}

Mettre à jour les problèmes connus

  • [x] Certaines API ci-dessus prennent un uint, doivent prendre une Rune.
  • [ ] Nécessité d'implémenter IComparable family
  • [ ] RuneCount/RuneLen ont besoin de meilleurs noms, voir les docs (ils devraient peut-être être Utf8BytesNeeded ?)
  • [ ] Ci-dessus, les API "ustring" font référence à mon API UTF8, cela ne fait vraiment pas partie de l'API, mais nous devrions considérer s'il existe une passerelle vers System.String dans certaines d'entre elles, ou vers Utf8String.
api-needs-work area-System.Runtime up-for-grabs

Commentaire le plus utile

Je l'ai dit dans le numéro d'origine et je le redis. Abandonner ce que dit une norme parce que vous n'aimez pas la phrase confondra plus qu'elle ne résoudra, et, étant donné qu'il existe une page de code runique dans Unicode, cela la confond encore plus.

Le nom est faux.

Tous les 106 commentaires

Vous attendez-vous à ce que la représentation en mémoire soit des chaînes d'objets 32 bits, ou traduite à la volée ? Qu'en est-il de la mémoire doublant si l'ancien? Quel est l'impact sur les performances si ce dernier ?

Est-ce que nommer une technologie liée à Unicode d'après un script particulier pris en charge par Unicode (et une technologie pour améliorer la prise en charge du plan astral après un script BMP, en plus) est une bonne idée ?

Je pense que la proposition (et peut-être qu'elle doit être rendue plus explicite) est que la représentation en mémoire des chaînes ne change pas du tout. Le type Rune représente simplement un point de code 21 bits individuel distinct (stocké sous la forme d'un int 32 bits). Les méthodes faisant référence à des points de code pourraient potentiellement renvoyer un Rune la place. Il y a probablement une fonctionnalité dans string qui vous permettrait d'énumérer les Rune .

Je pense qu'il y a quelques points évidents sur lesquels nous devons obtenir un consensus pour quelque chose comme ça:

  1. Y a-t-il une valeur significative à créer un type Rune plutôt que d'utiliser Int32 comme le font les méthodes actuelles ?
  2. Le mot "rune" est-il vraiment un bon choix ?

Pour répondre (1), je pense que nous avons besoin d'une description plus complète de la façon dont Rune serait exposé, quelles méthodes le recevraient et le renverraient, etc. Et pour déterminer si c'est mieux que de les traiter avec Int32 la place.

Quant au (2), j'hésite moi-même un peu. "Rune" est une sorte de mot ésotérique en anglais et a des connotations inhabituelles pour son utilisation dans ce contexte. Il y a aussi le point que d'autres soulèvent : il se heurte à un autre concept Unicode. Lorsque je fais une recherche sur "Unicode Rune", j'obtiens principalement des résultats pour le bloc Runic Unicode, et seulement quelques documentations en langage Go.

char est à la fois un demi-mot et un mot entier ; et vous devez inspecter son environnement pour déterminer lequel - comme le courant représente une demi-lettre ou une lettre entière.

Peut-être System.character où c'est toujours une lettre complète... :sunglasses:

char est un peu une représentation terrible et même pour les langues ascii/latin uniquement ; la montée des emoji continuera d'imprégner; cela signifie que char est un chèque et peut-être vérifier le prochain type char

@NickCraver sur Twitter

Alors que utf8 est un encodage à largeur variable ; il est rare (voire pas du tout ?) qu'un utilisateur veuille traiter avec des demi-caractères ; à la fois pour utf8 et utf32.

Un type 32 bits fonctionnerait bien pour l'énumération.

Plus difficile serait indexOf, Length, etc. pour une perspective de performance ou de mémoire.

  1. le tableau d'octets est la meilleure représentation pour un format opaque ; ex : conserver le format dans son format d'origine ou un format définitif (transfert de fichier, mise sur fil etc)
  2. le tableau d'octets est la meilleure représentation de la bande passante et de la taille de la mémoire
  3. le tableau d'octets est cohérent avec la position et l'indexOf, la longueur, etc. en termes d'octets

Cependant, lorsque vous commencez à vous soucier des caractères réels, des majuscules, des fractionnements sur les caractères; comprendre ce qu'est un caractère, l'octet devient une largeur variable. Char ne rend pas cela vraiment meilleur; il double la taille des plus petits caractères ; comprend plus de caractères, mais est toujours de largeur variable.

Pour cela, une valeur 32 bits peut être très utile du point de vue du code utilisateur. Cependant, il a des problèmes avec la position, la longueur et les éléments secondaires (indexOf, etc.)

Je suis très intéressé par une chaîne ascii uniquement et une chaîne utf8 "Implémentation de chaîne compacte" https://github.com/dotnet/coreclr/issues/7083; pour un traitement rapide des chaînes ascii uniquement

Cependant, allant à l'encontre de tout ce que je disais là-bas ... Je me demande à quoi ressemblerait une représentation 32 bits d'utf8? La position correspondrait à la position ; la recherche de caractères serait rapide car elle est en ascii, les éléments sont dans des tailles natives, etc. comment cela se comparerait-il au traitement de chaque octet ou caractère pour déterminer sa taille?

La conversion vers et depuis serait plus coûteuse ; il s'agirait donc davantage d'un format de traitement ; qu'un format de stockage.

@migueldeicaza , si je comprends bien, vous ne faites référence qu'à l'extension du format de caractère unique de 16 bits à 32 bits afin que toutes les représentations soient contenues dans la valeur; plutôt que la possibilité d'une demi-valeur - plutôt que nécessairement le format interne.

Cependant, des éléments à prendre en compte (c'est-à-dire la relation entre la position et le coût de la recherche, etc.)

A part: Swift traite également des formats de caractères entiers

Swift propose plusieurs manières d'accéder aux représentations Unicode des chaînes. Vous pouvez itérer sur la chaîne avec une instruction for-in pour accéder à ses valeurs de caractères individuelles en tant que clusters de graphèmes étendus Unicode. Ce processus est décrit dans Travailler avec des caractères.

Vous pouvez également accéder à une valeur String dans l'une des trois autres représentations compatibles Unicode :

  • Une collection d'unités de code UTF-8 (accessible avec la propriété utf8 de la chaîne)
  • Une collection d'unités de code UTF-16 (accessible avec la propriété utf16 de la chaîne)
  • Une collection de valeurs scalaires Unicode 21 bits, équivalentes à la forme de codage UTF-32 de la chaîne (accessible avec la propriété unicodeScalars de la chaîne)

Je l'ai dit dans le numéro d'origine et je le redis. Abandonner ce que dit une norme parce que vous n'aimez pas la phrase confondra plus qu'elle ne résoudra, et, étant donné qu'il existe une page de code runique dans Unicode, cela la confond encore plus.

Le nom est faux.

@mellinoe

La Rune fournirait de nombreuses opérations que vous attendez aujourd'hui sur un Char, comme ToLower[Invariant], ToUpper[Invariant], ToTitle, IsDigit, IsAlpha, IsGraphic, IsSymbol, IsControl.

De plus, il fournirait des éléments tels que :

  • EncodeRune (encode une rune dans un tampon d'octets)
  • RuneUtf8Len (retourne le nombre d'octets nécessaires pour encoder la rune en UTF8),
  • IsValid (toutes les valeurs Int32 ne sont pas valides)

Et interop à la chaîne et Utf8string au besoin.

J'ai porté/ajusté la prise en charge de la chaîne Go sur .NET, et il offre une vue de ce à quoi ressemblerait ce monde (c'est sans aucune aide à l'exécution):

https://github.com/migueldeicaza/NStack/tree/master/NStack/unicode

@benaadams a dit :

Je me demande à quoi ressemblerait une représentation 32 bits d'utf8? La position correspondrait à la position ; la recherche de caractères serait rapide car elle est en ascii, les éléments sont dans des tailles natives, etc. comment cela se comparerait-il au traitement de chaque octet ou caractère pour déterminer sa taille?

UTF8 est une représentation en mémoire, qui continuerait d'exister et continuerait d'être la représentation (et, espérons-le, il s'agit du codage interne à plus long terme pour les futures chaînes dans .NET).

Vous décoderiez les chaînes UTF16 existantes (System.String) ou les chaînes UTF8 à venir (Utf8String) non pas en caractères (pour la raison pour laquelle vous et moi sommes d'accord), mais en runes.

Quelques exemples, convertissez une chaîne Utf8 en runes :

https://github.com/migueldeicaza/NStack/blob/6a071ca5c026ca71c10ead4f7232e2fa0673baf9/NStack/strings/ustring.cs#L756

Une chaîne utf8 contient-elle une rune :

https://github.com/migueldeicaza/NStack/blob/6a071ca5c026ca71c10ead4f7232e2fa0673baf9/NStack/strings/ustring.cs#L855

Je viens de remarquer que je n'ai pas implémenté l'indexeur ("Obtenez-moi la n-ième rune")

La vitesse d'accès à la Nième rune dans une chaîne est fonction du stockage, pas de la Rune elle-même. Par exemple, si votre stockage est UTF32, vous avez un accès direct à chaque rune. C'est académique, car personne ne l'utilise. L'accès au Nième élément sur UTF16 et UTF8 nécessite le balayage correct des éléments composant la chaîne (octets ou entiers 16 bits) pour déterminer la bonne frontière. À ne pas confondre avec String[int n] { get; } qui ne renvoie que le n-ième caractère, quelle que soit son exactitude.

@benaadams Le personnage Swift est un niveau supérieur à une rune. Les caractères de Swift sont des "groupes de graphèmes étendus" qui sont constitués d'une ou plusieurs runes qui, lorsqu'elles sont combinées, produisent un caractère lisible par l'homme.

Ainsi, le caractère Swift n'a pas une taille fixe de 32 bits, il est de longueur variable (et nous devrions également avoir cette construction, mais qui appartient à un type de données différent). Voici l'exemple de cette page, mais cela s'étend également au réglage de la teinte d'un emoji :

Voici un exemple. La lettre é peut être représentée comme le scalaire Unicode unique é (LETTRE MINUSCULE LATINE E AVEC AIGU, ou U + 00E9). Cependant, la même lettre peut également être représentée par une paire de scalaires - une lettre standard e (LETTRE MINUSCULE LATINE E ou U + 0065), suivie du scalaire COMBINANT ACCENT AIGU (U + 0301). Le scalaire COMBINING ACUTE ACCENT est appliqué graphiquement au scalaire qui le précède, transformant un e en un é lorsqu'il est rendu par un système de rendu de texte compatible Unicode.

Juste pour moi, le mot grapheme serait plus auto-descriptif.

Mes deux cents sur le nom, citant à nouveau le Go post sur les cordes avec emphase :

« Point de code » est un peu long, alors Go introduit un terme plus court pour le concept : rune. Le terme apparaît dans les bibliothèques et le code source, et signifie exactement la même chose que "code point" , avec un ajout intéressant.

Je suis à 100% d'accord avec @blowdart , l'appeler rune est juste déroutant et faux. La norme unicode mentionne trois points de code juste dans la première page du chapitre d'introduction mais le terme rune n'apparaît nulle part.

S'il s'agit d'un point de code, il doit être nommé point de code , aussi simple que cela.

Si le terme rune n'est jamais apparu dans la norme, ça pourrait aller, le problème est qu'il apparaît plusieurs fois dans le chapitre 8, en relation avec les runes. Ce n'est pas seulement faux, c'est activement confondre le sujet avec un autre.

Juste pour moi, le mot grapheme serait plus auto-descriptif.

S'il s'agit de points de code 32 bits, le terme grapheme serait déroutant car un graphème est encore autre chose.

J'ai souvent voulu un type de données de point de code (pas depuis longtemps, car ce sur quoi j'ai travaillé a changé, mais il y a quelques années, je l'ai beaucoup voulu et j'ai écrit des solutions partielles qui se chevauchent pour certaines parties de ce besoin et aurait pu le faire avec une bibliothèque bien testée). Je ne vois pas pourquoi cela ne devrait pas s'appeler quelque chose comme CodePoint . La plupart des gens qui se rendent compte qu'ils avaient besoin d'un tel type penseraient probablement en termes de points de code de toute façon, pas en termes de runes ; ou bien en termes de points de code et de runes en tant que parties distinctes de leur tâche. Les runes/runes sont encore utilisées. Je n'ai besoin d'utiliser des runes qu'environ une fois par an, et généralement avec du parchemin et de l'encre plutôt que quelque chose de numérique, mais il y a certainement des gens qui les traitent aussi numériquement. (Même avec des données du 20e siècle, je connais un cas où elles sont utilisées pour archiver des données de la Seconde Guerre mondiale).

Le graphème est encore plus délicat, car on veut souvent aller octets → chars (déjà bien géré par .NET) puis chars → points de code, puis points de code → graphèmes.

signalant cela comme à saisir pour le moment.

Prochaines étapes : Ce que nous recherchons est : une proposition formelle qui inclura les commentaires ci-dessus (la dénomination réelle du type et les avantages de l'utiliser par rapport à la simple utilisation d'un Int32).

J'ai mis à jour le problème, à la fois avec l'API proposée et une implémentation initiale :

https://github.com/migueldeicaza/NStack/blob/master/NStack/unicode/Rune.cs

En ce qui concerne la dénomination du type, il s'agit à la fois d'avoir un endroit où vous pouvez rechercher les opérations valides sur le type, ainsi que d'avoir des capacités spécifiques au type (voir l'implémentation pour quelques exemples).

@migueldeicaza avant de le signaler comme prêt pour examen, que pensez-vous des préoccupations concernant la dénomination réelle du type, pensez-vous que CodePoint pourrait peut-être mieux décrire ce qu'est le type ?

Je pense que l'argument pour utiliser le point de code comme nom est faible.

L'utiliser est une idée terrible, à long terme, cela doit remplacer chaque utilisation de "char" dans le code existant - si nous espérons obtenir un support Unicode approprié.

J'aurais aimé pouvoir utiliser "char" comme le fait Rust, mais malheureusement, nous l'avons déjà pris et nous en avons un cassé.

Allez avoir embrassé ce nom est un bon précédent.

Je suis d'accord que code point n'est pas le bon terme à utiliser ici. À tout le moins, selon la norme Unicode, il n'inclut pas les valeurs supérieures à 10FFFF (http://unicode.org/glossary/#code_point).

Je n'aime pas le terme rune . Je pense qu'il a une utilisation existante dans Unicode et ailleurs qui ne fera que semer la confusion dans l'ensemble. Je pense aussi qu'il a de bonnes chances d'entrer en conflit avec les types d'utilisateurs existants (en particulier pour des choses comme Unity, où une "Rune" peut représenter un objet de jeu spécifique).

Cependant, j'aime l'idée d'un type qui couvre le type C++ 11 char32_t , juste avec un nom différent.

Il y a quelque chose à dire pour Char32 . C'est au point, c'est analogue aux noms de type des types intégraux. Il parle au niveau conceptuel du caractère, plutôt qu'au niveau du point de code. Ce n'est pas le nom d'un script.

Puisque nous envisageons d'avoir nint , que diriez-vous de nchar ?

Le précédent serait dans les bases de données nchar et nvarchar

nchar est le caractère national/caractère national et nvarchar est le caractère national variable/caractère national variable ; quels sont les types de champs dans lesquels vous pouvez stocker l'unicode, ainsi que certaines normes ISO - vous ne savez pas lesquelles, peut-être SQL ?

Quelle est cette utilisation Unicode de rune ? C'est nouveau pour moi.

U+16A0 à U+16F8

Il est utilisé pour faire référence à une page de code spécifique dans la norme Unicode. Il a été évoqué plusieurs fois dans ce fil : http://unicode.org/charts/PDF/U16A0.pdf

Ah runique, pas runique.

Le nom de sauvegarde (System.Rune ou System.Char32) n'est pas aussi important que l'étiquette qui sera projetée dans C#.

Premièrement: oui, oui, et plus de cela s'il vous plaît. J'adore cette idée (honnêtement, j'ai une idée similaire depuis longtemps maintenant). En fait, nous utilisons une classe de chaîne personnalisée et une structure de caractères dans notre compatibilité Git plus tard dans Visual Studio depuis un certain temps maintenant (Git parle en Utf-8 et le transcodage est très lent).

En ce qui concerne les noms de méthodes statiques, pouvons-nous éviter les noms courts arbitraires, s'il vous plaît ? Étant donné que Char.IsPunctuation est la méthode actuelle, pouvons-nous s'il vous plaît refléter cela avec Rune.IsPunctuation ou similaire ?

En supposant (toujours dangereux) que cela soit accepté, pouvons-nous avoir un rune ou c32 intrinsèque, ou simplement remplacer complètement char #$4$#$ par l'implémentation System.Rune ?

Je suggère unichar ou uchar bien que uchar ressemble à un caractère non signé. Quel que soit le choix, j'espère que nous obtiendrons un alias spécifique à la langue. Personnellement, je suis un grand fan de l'utilisation des alias de langage pour les types primitifs.

Je suis également d'accord avec @whoisj - Je préférerais certainement les noms de méthode complets aux raccourcis/abréviations.

Je suis également d'accord avec @whoisj - Je préférerais certainement les noms de méthode complets aux raccourcis/abréviations.

IMO, un langage (et ses bibliothèques) doit choisir soit des noms complets et abrégés, soit se concentrer sur les abréviations (comme C avec strcmp, memcpy, etc.)

ou simplement remplacer complètement $#$ char $#$ par l'implémentation System.Rune ?

Ce serait un changement radical pour des raisons assez évidentes.

Ce serait un changement radical pour des raisons assez évidentes.

Mes commentaires étaient principalement de la langue et de la joue et pleins d'espoir. Un type de caractère 16 bits était une erreur dès le départ.

Bonne prise sur le nommage, va corriger.

Il existe d'autres petites incohérences dans l'API fournie, nous allons également essayer de les corriger.

@migueldeicaza

Ah runique, pas runique.

Runique est l'adjectif, rune le nom. Tous les caractères runiques sont des runes.

_Runic_ est l'adjectif, _rune_ le nom. Tous les caractères runiques sont des runes.

Aussi juste qu'il semble "Cortana : définir _'rune'_" propose :

une lettre d'un ancien alphabet germanique, lié à l'alphabet romain.

Ah oui, chaque fois que je vois le mot "rune", je pense immédiatement à ce chapitre obscur sur une spécification que personne n'a lu qui parle de "The Runic Unicode Block".

😆 Je pense aux souvenirs d'enfance de la lecture de Tolkien.

ᛁ᛫ᚦᛁᛜᚲ᛫ᛟᚠ᛫ᚱᚢᚾᛖᛋ

Ouais, je ne pense pas spécifiquement à la spécification, mais je pense au type de caractères auxquels la spécification fait référence.

Vous dites rune et je pense à la magie, à la fantaisie, aux énigmes énigmatiques, aux langues anciennes, etc.

Je suis heureux que vous ne voyiez pas le mot "rune" et que vous pensiez immédiatement "Ah, cela fait clairement référence au bloc runique Unicode 7.0 dont la valeur sera limitée à ces valeurs uniques dans la plage 16A0..16F8".

Je sais que Tanner est une seule voix ici, et certains d'entre vous pensent encore "Mais Miguel, je vois le mot 'rune' et je pense immédiatement à un type de données qui ne pourrait contenir que 88 valeurs possibles". Si c'est un problème avec lequel vous vous débattez, mon frère/sœur, j'ai une nouvelle pour vous : vous avez de plus gros poissons à faire frire.

Je suis ce fil depuis un moment avec un mélange d'excitation et d'hésitation depuis un peu plus d'un mois. J'ai assisté à la conférence Internationalization and Unicode le mois dernier, et aucune des présentations ne traitait de .NET. Il y a un problème de perception avec le .NET Framework ; un qui n'est pas nécessairement immérité compte tenu de l'histoire de ses caractéristiques de mondialisation. Cela étant dit, j'adore programmer en C# et je veux absolument voir de nouvelles fonctionnalités qui renforcent la place de .NET dans une communauté véritablement mondiale. Je pense que cette proposition est un bon pas dans cette direction pour adopter les normes que la communauté de l'internationalisation attend des logiciels.

Mon hésitation a surtout été sur les querelles sur le nom du type. S'il est vrai que les concepteurs de Go ont choisi le nom "rune", c'est problématique pour la raison énumérée ci-dessus à plusieurs reprises : il existe des points de code qui sont correctement appelés runes. Il m'est difficile d'être d'accord avec une proposition qui tente de se rapprocher d'une norme respectée, puis redéfinit la terminologie qui fait partie de la spécification. De plus, l'argument selon lequel la plupart des développeurs ignorent le terme est spécieux étant donné que les développeurs les plus intéressés par l'utilisation correcte de ce type sont plus susceptibles de comprendre la spécification Unicode et d'avoir une bonne idée de ce qu'est réellement une "rune". Imaginez la bizarrerie qui pourrait exister si vous mélangez la terminologie :

Rune.IsRune(new Rune('ᛁ')); // evaluates to true
Rune.IsRune(new Rune('I')); // evaluates to false

Bien sûr, j'ai choisi la voie facile ici, en critiquant sans fournir de nouveau nom. Je pense que la suggestion précédente de CodePoint est l'option la plus auto-descriptive (et elle apparaît dans la description originale du problème), mais char32 aurait plus de parité avec les types primitifs existants (bien que je le ferais hésiter à dire que chaque point de code n'est pas un caractère). Si l'objectif est de créer une meilleure prise en charge d'Unicode dans .NET, je suis absolument favorable à ce chemin, mais la meilleure façon de le faire est de suivre les spécifications.

Trois propositions :

  1. La classe Rune manque le critique "IsCombining". Sans cela, nous ne pouvons pas convertir une série de runes (points de code) en une série de graphèmes.
  1. J'aimerais aussi avoir une classe Grapheme correspondante. Un graphème dans ce contexte n'est en réalité qu'une liste d'une ou plusieurs runes (points de code) de sorte que la première rune ne se combine pas et que les autres runes se combinent. Le cas d'utilisation concerne le cas où un développeur doit gérer des blocs de "caractères visibles". Par exemple, a + GRAVE est deux runes qui forment un graphème.

  2. Dans le réseautage, nous obtenons souvent un tas d'octets que nous devons transformer en un objet semblable à une "chaîne" où les octets peuvent ne pas être complets (par exemple, on nous dit que certains octets, mais le dernier octet d'une séquence multi-octets n'a pas ' n'est pas encore arrivé). Je ne vois aucun moyen évident de convertir un flux d'octets en un flux de runes de sorte que manquer le dernier octet d'une séquence multi-octets soit considéré comme une situation normale qui sera corrigée lorsque nous aurons le prochain ensemble d'octets.

Et enfin, veuillez utiliser des noms Unicode et appelez cela un CodePoint. Oui, le consortium Unicode fait un travail terrible pour expliquer la différence. Mais la solution est d'ajouter une documentation claire et utilisable ; toute autre chose confond le problème au lieu d'aider à clarifier.

Je ne sais pas par où commencer sur la requête de combinaison, ni Go, Rust ou Swift ne font surface sur une telle API sur rune, Character ou Unicode Scalar (leurs noms pour System.Rune ). Veuillez fournir une proposition d'implémentation.

Sur les grappes de graphèmes, c'est une bonne idée, il devrait être suivi indépendamment de System.Rune . Pour ce que ça vaut, Swift utilise Character pour cela, mais Swift n'est pas non plus un excellent modèle pour gérer les chaînes.

Transformer des flux d'octets en une rune appropriée est un problème qui appartient à une API de niveau supérieur. Cela dit, vous pouvez regarder mon implémentation ustring qui utilise le même substrat que mon implémentation System.Rune pour voir comment ces tampons sont mappés dans des chaînes utf8 :

https://github.com/migueldeicaza/NStack/blob/master/NStack/strings/ustring.cs

Documentation, que je n'ai pas encore mise à jour depuis que j'ai introduit System.Rune dans l'API, mais qui la couvre :

https://migueldeicaza.github.io/NStack/api/NStack/NStack.ustring.html

En ce qui concerne le nommage, Rust est clairement le meilleur avec char , mais nous avons foiré celui-là. Le deuxième meilleur est Go with rune . Tout ce qui dépasse quatre caractères ne sera qu'une nuisance pour les gens qui feront ce qu'il faut.

Je suis désolé; Je pense que CodePoint est un très bon nom. C'est explicite, mémorable et se complète automatiquement avec c p .

IsCombining serait certainement nécessaire, mais il en va de même pour la classe de combinaison et une fois que nous avons que IsCombining est en grande partie du sucre car il ne s'agit que de IsCombining => CombiningClass != 0 ou IsCombining => CombiningClass != CombiningClass.None . Les clusters de graphèmes seraient en effet à nouveau en dehors de celui-ci, mais le point de départ serait de connaître la classe de combinaison pour le clustering par défaut, la réorganisation, etc.

CodePoint est un excellent nom pour un type sur les points de code, et quatre caractères ne sont pas une limite à laquelle nous devons faire face avec d'autres types très utilisés ; string est 50% plus grand et ne nous empêche pas de l'utiliser régulièrement. Quatre lettres choisies au hasard seraient un meilleur nom que de répéter l'erreur de Go.

Étant donné que uint n'est pas conforme au CLS, il n'y a pas de ctor conforme au CLS qui couvre les plans astraux. int serait également nécessaire.

Les conversions implicites bidirectionnelles peuvent entraîner de mauvaises choses avec des surcharges, donc une direction devrait peut-être être explicite. Il n'est pas clair lequel. D'une part, uint / int est plus large que les points de code car les valeurs inférieures à 0 ou supérieures à 10FFFF 16 ne sont pas significatives, et avoir cette conversion implicite permet une utilisation plus rapide de plus d'API existantes pour Nombres. D'un autre côté, je peux voir vouloir passer d'un nombre à un point de code plus souvent que l'inverse.

Puisque uint n'est pas conforme à CLS, il n'y a pas de ctor conforme à CLS qui couvre les plans astraux. int serait également nécessaire.

A moins qu'un nouveau type intrinsèque ne soit introduit dans le langage commun.

JonHanna -- voulez-vous dire que ces trois constructeurs :
public static implicite opérateur uint (Rune rune);
opérateur implicite statique public Rune (char ch);
opérateur implicite statique public Rune (valeur uint) ;

devrait être "int" au lieu de "uint". AFAICT, int couvre facilement l'ensemble des plans astraux (non BMP).

@PeterSmithRedmond Je veux dire qu'en plus des deux constructeurs, l'un prenant char et l'autre prenant uint , il devrait y en avoir un prenant int , mais oui, il devrait aussi y avoir un int opérateur de conversion (juste ce qui devrait être implicit et ce que explicit est une autre question). Il n'y a pas de mal à avoir uint aussi pour les langues qui peuvent l'utiliser ; c'est un match assez naturel après tout.

Si cela doit remplacer System.Char, il devrait être possible de faire de l'"arithmétique" dessus (c'est-à-dire ==, !=, >, <unsure on +, -, *, /) et plus important encore, il devrait prendre en charge les littéraux de this tapez par exemple je devrais pouvoir écrire :

rune r = '𐍈'; // Ostrogothic character chose on purpose as in UTF16 will be a "surrogate pairs"


image

Si ce n'est pas rune , le seul autre synonyme de character qui pourrait fonctionner est peut-être letter ?

nom

  1. une communication écrite ou imprimée adressée à une personne ou à une organisation et généralement transmise par la poste.
  2. un symbole ou un caractère qui est traditionnellement utilisé dans l'écriture et l'impression pour représenter un son de la parole et qui fait partie d'un alphabet.
  3. une pièce en caractères d'imprimerie portant un tel symbole ou caractère.

Bien que cela entrerait en conflit avec la lettre contre le nombre

Lettre a une signification encore plus précise en unicode (et Net en général) que rune.

Je pense que si nous voulons en faire un type de caractère Unicode, nous devons suivre les conventions de dénomination d'Unicode; ce qui signifie _"point de code"_.

Point de code . (1) Toute valeur dans l'espace de code Unicode ; c'est-à-dire la plage d'entiers de 0 à 10FFFF16. (Voir la définition D10 dans la section 3.4, Caractères et codage .) Tous les points de code ne sont pas attribués à des caractères codés. Voir type de point de code . (2) Une valeur, ou une position, pour un caractère, dans n'importe quel jeu de caractères codés.

Ou peut-être que nous abandonnons et appelons un canard un "canard" et nous y référons en tant que caractères Unicode (alias uchar ).

Pourquoi ne pas simplement résoudre ce problème pour utiliser System.CodePoint la place ?
À mon humble avis, c'est plus approprié en termes de terminologie d'Unicode, et d'autres personnes dans le monde Java l'utilisent. Donc, au lieu d'avoir un terme par nous-mêmes, respectons les termes Unicode. Cela a plus de sens et est plus universel en termes de caractères généraux et d'implémentation de chaîne dans .NET, sachant également que String dans .NET est une collection de caractères et que cette collection de caractères est basée sur Unicode.

Je le sais, car j'ai vécu à la fois dans les mondes Java et .NET.
Et peut-être commençons-nous à avoir un projet de mise en œuvre à ce sujet.

Il y a vraiment deux composants de cela et les deux seraient nécessaires (CodeUnit dans https://github.com/dotnet/corefxlab/issues/1799 par @GrabYourPitchforks)

C# keyword      Ugly Long form      Size
----------------------------------------
ubyte      <=>  System.CodeUnit    8 bit  - Assumed Utf8 in absence of encoding param
uchar      <=>  System.CodePoint  32 bit

CodeUnit / ubyte sont importants pour représenter l'encodage à largeur variable et pour une utilisation dans Span<ubyte> afin de s'assurer que les API de texte sont disponibles sur les types de texte mais pas sur les octets bruts.

CodePoint / uchar est important pour un traitement sensible ; par exemple .IndexOf(❤) comme ubyte seul ne peut pas être utilisé pour rechercher un caractère unicode multi-octets ; et énumérer plus ubyte s serait périlleux, donc l'énumérateur devrait travailler en uchar unités.

En combinant les deux propositions, ce serait quelque chose comme

using System;
using System.Runtime.InteropServices;

// C# Keywords
using ubyte = System.CodeUnit;
using uchar = System.CodePoint;
using uspan = System.Utf8Span;
using ustring = System.Utf8String;

namespace System
{
    public ref struct Utf8Span
    {
        private readonly ReadOnlySpan<ubyte> _buffer;

        public Utf8Span(ReadOnlySpan<ubyte> span) => _buffer = span;
        public Utf8Span(uspan span) => _buffer = span._buffer;
        public Utf8Span(ustring str) => _buffer = ((uspan)str)._buffer;
        public Utf8Span(ReadOnlyMemory<ubyte> memory) => _buffer = memory.Span;

        // Returns the CodeUnit index, not CodePoint index
        public int IndexOf(char value) => IndexOf(value, 0);
        public int IndexOf(char value, int startIndex) => IndexOf(value, 0, _buffer.Length);
        public int IndexOf(char value, int startIndex, int count);
        public int IndexOf(char value, StringComparison comparisonType);

        public int IndexOf(uchar value) => IndexOf(value, 0);
        public int IndexOf(uchar value, int startIndex) => IndexOf(value, 0, _buffer.Length);
        public int IndexOf(uchar value, int startIndex, int count);
        public int IndexOf(uchar value, StringComparison comparisonType);

        public uspan Substring(int codeUnitIndex);
        public uspan Substring(int codeUnitIndex, int codePointCount);

        public bool StartsWith(uchar ch) => _buffer.Length >= 1 && _buffer[0] == ch;
        public bool StartsWith(ustring str) => StartsWith((uspan)str);
        public bool StartsWith(uspan value) => _buffer.StartsWith(value._buffer);
        public bool EndsWith(uchar ch) => _buffer.Length >= 1 && _buffer[0] == ch;
        public bool EndsWith(ustring str) => EndsWith((uspan)str);
        public bool EndsWith(uspan value) => _buffer.EndsWith(value._buffer);

        public Enumerator GetEnumerator() => new Enumerator(this);

        // Iterates in uchar steps, not ubyte steps
        public ref struct Enumerator
        {
            public Enumerator(uspan span);

            public uchar Current;
            public bool MoveNext();
            public void Dispose() { }
            public void Reset() => throw new NotSupportedException();
        }
    }

    public class Utf8String
    {
        private readonly ReadOnlyMemory<ubyte> _buffer;

        public Utf8String(ustring str) => _buffer = str._buffer;
        public Utf8String(ReadOnlyMemory<ubyte> memory) => _buffer = memory;

        public bool StartsWith(uchar ch) => ((uspan)this).StartsWith(ch);
        public bool StartsWith(ustring value) => ((uspan)this).StartsWith(value);
        public bool StartsWith(uspan value) => ((uspan)this).StartsWith(value);
        public bool EndsWith(uchar ch) => ((uspan)this).EndsWith(ch);
        public bool EndsWith(ustring value) => ((uspan)this).EndsWith(value);
        public bool EndsWith(uspan value) => ((uspan)this).EndsWith(value);

        public static implicit operator uspan(ustring value) => new uspan(value._buffer);

        // Returns the CodeUnit index, not CodePoint index
        public int IndexOf(char value) => IndexOf(value, 0);
        public int IndexOf(char value, int startIndex) => IndexOf(value, 0, _buffer.Length);
        public int IndexOf(char value, int startIndex, int count);
        public int IndexOf(char value, StringComparison comparisonType);

        public int IndexOf(uchar value) => IndexOf(value, 0);
        public int IndexOf(uchar value, int startIndex) => IndexOf(value, 0, _buffer.Length);
        public int IndexOf(uchar value, int startIndex, int count);
        public int IndexOf(uchar value, StringComparison comparisonType);

        public ustring Substring(int codeUnitIndex);
        public ustring Substring(int codeUnitIndex, int codePointCount);

        public uspan.Enumerator GetEnumerator() => ((uspan)this).GetEnumerator();
    }

    [StructLayout(LayoutKind.Auto, Size = 1)]
    public struct CodeUnit : IComparable<ubyte>, IEquatable<ubyte>
    {
        private readonly byte _value;

        public CodeUnit(ubyte other) => _value = other._value;
        public CodeUnit(byte b) => _value = b;

        public static bool operator ==(ubyte a, ubyte b) => a._value == b._value;
        public static bool operator !=(ubyte a, ubyte b) => a._value != b._value;
        public static bool operator <(ubyte a, ubyte b) => a._value < b._value;
        public static bool operator <=(ubyte a, ubyte b) => a._value <= b._value;
        public static bool operator >(ubyte a, ubyte b) => a._value > b._value;
        public static bool operator >=(ubyte a, ubyte b) => a._value >= b._value;

        public static implicit operator byte(ubyte value) => value._value;
        public static explicit operator ubyte(byte value) => new ubyte(value);

        // other implicit conversions go here
        // if intrinsic then casts can be properly checked or unchecked

        public int CompareTo(ubyte other) => _value.CompareTo(other._value);

        public override bool Equals(object other) => (other is ubyte cu) && (this == cu);

        public bool Equals(ubyte other) => (this == other);

        public override int GetHashCode() => _value;

        public override string ToString() => _value.ToString();
    }

    [StructLayout(LayoutKind.Auto, Size = 4)]
    public struct CodePoint : IComparable<uchar>, IEquatable<uchar>
    {
        private readonly uint _value;

        public CodePoint(uint CodePoint);
        public CodePoint(char ch);

        public static ValueTuple<uchar, int> DecodeLastCodePoint(ubyte[] buffer, int end);
        public static ValueTuple<uchar, int> DecodeLastCodePoint(ustring str, int end);
        public static ValueTuple<uchar, int> DecodeCodePoint(ubyte[] buffer, int start, int n);
        public static ValueTuple<uchar, int> DecodeCodePoint(ustring str, int start, int n);
        public static int EncodeCodePoint(uchar CodePoint, ubyte[] dest, int offset);
        public static bool FullCodePoint(ubyte[] p);
        public static bool FullCodePoint(ustring str);
        public static int InvalidIndex(ubyte[] buffer);
        public static int InvalidIndex(ustring str);
        public static bool IsControl(uchar CodePoint);
        public static bool IsDigit(uchar CodePoint);
        public static bool IsGraphic(uchar CodePoint);
        public static bool IsLetter(uchar CodePoint);
        public static bool IsLower(uchar CodePoint);
        public static bool IsMark(uchar CodePoint);
        public static bool IsNumber(uchar CodePoint);
        public static bool IsPrint(uchar CodePoint);
        public static bool IsPunctuation(uchar CodePoint);
        public static bool IsSpace(uchar CodePoint);
        public static bool IsSymbol(uchar CodePoint);
        public static bool IsTitle(uchar CodePoint);
        public static bool IsUpper(uchar CodePoint);
        public static int CodePointCount(ubyte[] buffer, int offset, int count);
        public static int CodePointCount(ustring str);
        public static int CodePointLen(uchar CodePoint);
        public static uchar SimpleFold(uchar CodePoint);
        public static uchar To(Case toCase, uchar CodePoint);
        public static uchar ToLower(uchar CodePoint);
        public static uchar ToTitle(uchar CodePoint);
        public static uchar ToUpper(uchar CodePoint);
        public static bool Valid(ubyte[] buffer);
        public static bool Valid(ustring str);
        public static bool ValidCodePoint(uchar CodePoint);

        public static bool operator ==(uchar a, uchar b) => a._value == b._value;
        public static bool operator !=(uchar a, uchar b) => a._value != b._value;
        public static bool operator <(uchar a, uchar b) => a._value < b._value;
        public static bool operator <=(uchar a, uchar b) => a._value <= b._value;
        public static bool operator >(uchar a, uchar b) => a._value > b._value;
        public static bool operator >=(uchar a, uchar b) => a._value >= b._value;

        // etc
    }
}

J'ai utilisé UnicodeScalar dans mes implémentations de prototypes pour faire référence à une valeur scalaire Unicode (valeurs comprises dans la plage U+0000..U+10FFFF, inclus ; à l'exclusion des points de code de substitution) et Utf8Char pour faire référence à l'unité de code UTF-8. On dirait que beaucoup de gens préfèrent _Rune_ au lieu de _UnicodeScalar_ parce que c'est moins long. Je m'en fous, mais je soulignerai que le terme "valeur scalaire Unicode" est le même terme utilisé par la spécification Unicode . ;)

Le .NET Framework a également le concept d'un "élément de texte", qui est un ou plusieurs scalaires qui, lorsqu'ils sont combinés, créent un seul graphème indivisible. Plus d'informations à ce sujet sur MSDN . En particulier, lorsque vous énumérez une chaîne, vous pouvez énumérer par unité de code ( Utf8Char ou Char ), valeur scalaire ( UnicodeScalar ) ou élément de texte, selon votre scénario particulier. Idéalement, nous prendrions en charge les trois types sur String et Utf8String.

La surface de l'API pour notre prototype n'est pas terminée et est sujette à des changements rapides, mais vous pouvez voir quelques réflexions en cours sur https://github.com/dotnet/corefxlab/tree/utf8string/src/System.Text.Utf8/System /Text et https://github.com/dotnet/corefxlab/blob/master/src/System.Text.Primitives/System/Text/Encoders/Utf8Utility.cs.

Un peu hors sujet :
L'"élément de texte" doit-il être la segmentation définie par "Grapheme Cluster Boundaries" dans UAX dotnet/corefx#29 ?

using System;
using System.Globalization;

class Program
{
    static void Main()
    {
        var e = StringInfo.GetTextElementEnumerator("👩🏻‍👦🏼👨🏽‍👦🏾‍👦🏿👩🏼‍👨🏽‍👦🏼‍👧🏽👩🏻‍👩🏿‍👧🏼‍👧🏾");
        while (e.MoveNext())
        {
            Console.WriteLine(e.GetTextElement());
        }
    }
}

résultat attendu:
👩🏻‍👦🏼
👨🏽‍👦🏾‍👦🏿
👩🏼‍👨🏽‍👦🏼‍👧🏽
👩🏻‍👩🏿‍👧🏼‍👧🏾

résultat actuel:
👩
🏻

👦
🏼
👨
🏽

👦
🏾

👦
🏿
👩
🏼

👨
🏽

👦
🏼

👧
🏽
👩
🏻

👩
🏿

👧
🏼

👧
🏾

UnicodeScalar est toujours super facile à taper. u s c Space (complétions automatiques) Puisque c'est le terme correct et le plus auto-descriptif, j'espère vraiment que nous l'obtiendrons.

@ufcpp C'est un bon point. N'hésitez pas à ouvrir un nouveau sujet pour cela. Si nous ne pouvons pas modifier le comportement pour des raisons de compatibilité, je suggérerais de déconseiller ce type et de créer un énumérateur de graphèmes conforme aux spécifications.

ubyte / uchar sont déroutants. Ils se lisent comme unsigned char / unsigned byte étant donné la convention établie avec ushort / uint / ulong . Peut-être que char8 / u8char et char32 / u32char sont plus clairs ?

Dans tous les cas, je pense que nous ne sommes pas alignés sur la question de savoir si les unités de code et les points de code UTF-8 sont :

  1. types de données primitifs de bas niveau dans .NET - comme byte , int
  2. un format de données pour convertir vers/depuis des primitives existantes - comme DateTime , Guid

Et ensuite, comment exposer les API liées aux points de code compte tenu de cette décision ?

L'option 1 signifie la gestion du texte via les primitives char8, char16 et char32 (et les accompagnements u8string, u16string et u32string) comme C++17. Ensuite, char32 en tant que rune est un mauvais nom, étant donné que nous avons déjà char16 en tant que char et avons également besoin d'un troisième nom pour char8 .

L'option 2 signifie que byte et int/uint sont "assez bons" pour stocker les unités de code UTF et les points de code. Cela implique que toutes les chaînes restent UTF-16. CodePoint / rune résout les problèmes de sémantique Code Point plutôt que de représentation binaire - et n'est pas destiné à IO .

IMO UTF-8/UTF-32 ne sont que des formats de données (option 2). Traitez-les comme des données (octet/int). CodePoint ressemble plus à DateTime ou Guid (un autre identifiant*) qu'à int pour moi - pas un type primitif de bas niveau, pas directement pris en charge dans IO (c'est-à-dire BinaryWriter), pas besoin d'intrinsèques.

@miyu Le prototype que nous proposons dans corefxlab est plus proche de l'option 1. Il existe des types de données spécifiques pour représenter les unités de code, et ces types de données sont destinés à la représentation interne des données textuelles et ne peuvent pas être utilisés pour transmettre des données textuelles sur le fil. (Comme vous l'avez souligné, .NET fonctionne déjà comme ceci aujourd'hui : System.Char est l'unité de code d'une chaîne UTF-16, mais System.Char ne peut pas être envoyé sur le réseau.)

De plus, il existe des API pour convertir entre byte[] / Span<byte> / etc. (il s'agit de la représentation binaire de toutes les données et convient aux E/S) et des types primitifs comme Utf8String / String / Guid / etc. Certains d'entre eux sont plus simples que d'autres. Par exemple, nous pouvons exposer une propriété pratique Utf8String.Bytes qui renvoie un ReadOnlySpan<byte> à utiliser dans les entrées/sorties, et ce getter de propriété peut avoir une complexité O(1). Nous n'introduirons pas une telle propriété sur le type String , bien que vous puissiez imaginer avoir une méthode de commodité String.ToUtf8Bytes() . Et même s'il existerait une propriété Utf8String.Bytes , le type élémentaire d'énumération sur une instance Utf8String directement ne serait pas byte . Ce serait Utf8CodeUnit (nom à déterminer) ou UnicodeScalar , selon ce que nous pensons être le plus logique pour les types d'applications que les développeurs veulent créer.

Idée idiote et décalée - qu'en est-il de wchar (_wide char_) ? Aujourd'hui, la plupart des environnements de compilateur C et C++ (en dehors de Windows) utilisent déjà wchar_t pour représenter l'équivalent fonctionnel d'une unité de code 32 bits. Windows est une exception notable, où wchar_t est défini comme étant un type 16 bits, mais les développeurs qui p/invoquent sur Windows aujourd'hui doivent déjà être conscients des différences de largeur de bits entre un .NET char et un style C char .

Le type / mot-clé wchar violerait nos conventions de dénomination, mais il suffit de le jeter pour examen.

Idée idiote sur le mur - qu'en est-il de wchar (caractère large) ?

Travaille pour moi

Le type / mot-clé wchar violerait nos conventions de nommage, ...

Il ne semble pas que nous allons obtenir un court mot-clé en langage C#

https://github.com/dotnet/apireviews/pull/64#discussion_r196962756 il semble extrêmement peu probable que nous introduisions des mots-clés de langage pour ces types car ceux-ci devraient être contextuels (c'est-à-dire selon qu'ils peuvent se résoudre en un type avec le nom du mot-clé qu'ils auraient encore à lier à ce type, plutôt que le type représenté par le mot-clé).

Donc, si nous voulons quelque chose de sympa... c'est-à-dire NotLotsOfCapitalFullWords ...

Bien que j'aime normalement les conventions de dénomination de .NET, un nom long est un peu offensant pour essentiellement un int qui sera également probablement utilisé dans les génériques et comme variables de boucle.

par exemple, personne ne le fait

foreach (Int32 i in list)
{
    // ...
}

Est-ce qu'ils? (Sûrement...)

foreach (UnicodeScalar us in str)
{
    // ...
}

Est bien pire

foreach (wchar c in str)
{
    // ...
}

Semble ok...

rune , wchar et uchar (suggéré sur un autre fil) me semblent tous bons. Des suggestions pour un pair de string ? wstring , ustring , ou autre ?

... et pourquoi ne pas obtenir un mot clé en langage C# ? Bien sûr, ne pas en avoir pour la première version a du sens, mais si cela va dans le futur, la gestion des chaînes ne pas avoir de mot-clé est non seulement malhonnête, mais ouvertement hostile à son adoption.

/CC @MadsTorgersen @jaredpar

pourquoi ne pas obtenir un mot clé en langage C# ?

Les nouveaux mots clés entraînent des changements de rupture 100 % du temps. Peu importe le mot que vous choisissez, il existe une entreprise qui a un type de ce nom qui est utilisé partout dans son projet. La seule option que nous ayons sont les mots-clés contextuels : var par exemple.

J'ai des sentiments mitigés quant à l'utilisation d'un mot-clé contextuel pour cela. Les mots-clés de type existants ( int , string , etc ...) ont un avantage concret sur le nom de type réel ( Int32 , String ) :

  • string : cela fait référence au type System.String dans l'assembly que le compilateur identifie comme corelib. Ce nom n'a aucune ambiguïté associée.
  • String : le compilateur n'a aucune compréhension de ce type. C'est juste un type comme un autre et passe par toutes les mêmes règles de recherche que les types que vous définissez. Il peut être équivalent à string ou ne pas l'être.

Une fois que nous avons introduit des mots-clés contextuels ici, alors rune pourrait être soit :

  • Le type System.Rune à l'intérieur de l'assembly corelib
  • Le type rune que vous avez défini il y a deux ans lorsque vous avez lu à propos Go .

La recherche de rune est tout aussi ambiguë que String donc je ne vois pas d'avantage ferme à l'avoir comme mot-clé contextuel.

BTW: c'est pourquoi vous devriez utiliser string et non String 😄

BTW: c'est pourquoi vous devriez utiliser string et non String

Dont 99% de la raison pour laquelle je pense que les gens veulent un mot-clé de langue. L'autre 1% étant juste "ça a l'air mieux" 😏

Pouce vers le bas pour une forte aversion pour le mot-clé "rune".

Un meilleur mot est glyphe, car il représente déjà le concept général d'un symbole élémentaire en typographie.

Rune est un type spécifique de glyphe qui est ironiquement défini par Unicode. Se référer à Go comme art antérieur est quelque peu ridicule. L'art antérieur pour les runes est ce qui a été écrit en 150 après JC et les pierres runiques physiques réelles. Pas ce que quelqu'un à Redmond pense qu'une rune est. Essayer de redéfinir des concepts existants comme celui-ci est inhabituel car .NET a généralement une surface d'API bien conçue. Il s'agit d'une rare exception de très mauvaise dénomination d'API et je tiens à exprimer mon mécontentement.

Un meilleur mot est glyphe, car il représente déjà le concept général d'un symbole élémentaire en typographie.

Le problème est que "Glyph" est un terme utilisé lors du rendu de l'unicode en texte visible (de: utf8everywhere.org )

Glyphe

Une forme particulière dans une police. Les polices sont des collections de glyphes conçues par un créateur de caractères. Il incombe au moteur de mise en forme et de rendu du texte de convertir une séquence de points de code en une séquence de glyphes dans la police spécifiée. Les règles de cette conversion peuvent être compliquées, dépendent des paramètres régionaux et sortent du cadre de la norme Unicode.

Se référer à Go comme art antérieur est quelque peu ridicule.

Utilisation du terme Rob Pike et Ken Thompson utilisé lors de la création d'Utf-8 https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt

Rob Pike travaille maintenant sur Go, c'est pourquoi il utilise le terme d'origine.

Rune est un type spécifique de glyphe qui est ironiquement défini par Unicode.

Runic est défini par Unicode, Rune n'est pas

Runic est défini par Unicode, Rune n'est pas

Je ne pense pas que ce soit une déclaration exacte, la dernière spécification Unicode (http://www.unicode.org/versions/Unicode11.0.0/UnicodeStandard-11.0.pdf) a 37 résultats pour "rune" (seulement 36 sont valides , le dernier fait partie d'un mot plus grand) et il est toujours utilisé pour désigner des lettres individuelles de l'alphabet runique.

Je ne pense pas que ce soit une déclaration exacte, la dernière spécification unicode a 37 résultats pour "rune"

Dans le corps du texte décrivant les motivations ; pas dans un nom de personnage ou un nom de bloc de texte (où son caractère runique et runique)

Dans le corps du texte décrivant les motivations ; pas dans un nom de personnage ou un nom de bloc de texte (où son caractère runique et runique)

D'accord, juste. Mais nous revenons ensuite au problème selon lequel la spécification Unicode actuelle ne définit pas le terme "Rune" et lorsqu'il est utilisé, c'est pour un texte informatif décrivant des "caractères runiques".

Ce qui est formellement défini et utilisé pour décrire les choses est "Code Point" et "Code Unit".

  • Même si, historiquement, le ou les créateurs originaux ont utilisé le terme "Rune", la spécification officielle ne le fait pas (et j'imagine qu'ils avaient de bonnes raisons de ne pas l'utiliser).

Doit être court ou son utilisation devient moche

int CountCommas(string str)
{
    int i = 0;
    foreach(UnicodeCodePoint c in str.AsUnicodeCodePoints())
    {
        if (c == ',') i++;
    }
}

string Trim(string str)
{
    int end = str.Length - 1;
    int start = 0;

    for (start = 0; start < Length; start++)
    {
        if (!UnicodeCodePoint.IsWhiteSpace(str.GetUnicodeCodePointAt(start)))
        {
            break;
        }
    }

    for (end = Length - 1; end >= start; end--)
    {
        if (!UnicodeCodePoint.IsWhiteSpace(str.GetUnicodeCodePointAt(start)))
        {
            break;
        }
    }

    return str.SubString(start, end);
}

vs

int CountCommas(string str)
{
    int i = 0;
    foreach(Rune c in str.AsRunes())
    {
        if (c == ',') i++;
    }
}

string Trim(string str)
{
    int end = str.Length - 1;
    int start = 0;

    for (start = 0; start < Length; start++)
    {
        if (!Rune.IsWhiteSpace(str.GetRuneAt(start)))
        {
            break;
        }
    }

    for (end = Length - 1; end >= start; end--)
    {
        if (!Rune.IsWhiteSpace(str.GetRuneAt(start)))
        {
            break;
        }
    }

    return str.SubString(start, end);
}

Pour la longueur, j'opterais totalement pour CodePoint.IsWhiteSpace et str.GetCodePointAt , mais Rune est aussi amusant et cela ne me dérange pas.

@ jnm2 Nous n'utiliserions pas GetCodePointAt en ce qui concerne les chaînes. C'est trop ambigu : nous ne savons pas si vous vouliez le char qui se trouvait à cet index (puisque tous les char - même les substituts non appariés - sont également des points de code valides) ou le scalaire / rune qui se trouvait à cet index.

@GrabYourPitchforks Est-ce GetRuneAt peut éviter le même problème, ou dites-vous que cela n'aurait aucun sens ?

@ jnm2 Je disais juste que CodePoint en particulier est trop ambigu dans ce scénario. Sinon, le nom de la méthode GetXyzAt doit correspondre au nom du type Xyz qui finit par entrer.

Pour votre information, l'implémentation principale est maintenant enregistrée (voir https://github.com/dotnet/coreclr/pull/20935). Donnez-lui un peu de temps pour se propager à corefx, puis les API de référence arriveront via https://github.com/dotnet/corefx/pull/33395. N'hésitez pas à laisser ce problème ouvert ou à le résoudre comme bon vous semble.

Je ne m'attends pas à influencer qui que ce soit ou à pouvoir changer quoi que ce soit, mais juste pour l'enregistrement :

Un meilleur mot est glyphe, car il représente déjà le concept général d'un symbole élémentaire en typographie.

Le problème est que "Glyph" est un terme utilisé lors du rendu de l'unicode en texte visible (de: utf8everywhere.org )

Ce raisonnement ne prend pas non plus en charge la rune, car "rune" est un terme utilisé depuis plus de mille ans à travers l'histoire, bien avant qu'Unicode, les transistors, Microsoft ou l'open source n'existent. Au moins, cela indique que certains appliquent arbitrairement différentes normes à différentes propositions, ce qui n'est évidemment pas cohérent, alors peut-être s'agit-il davantage de savoir qui a été le premier ou qui est le plus fort plutôt que l'argument le plus cohérent, que sais-je. Je suis juste un retardataire essayant de comprendre le processus mais cela n'a pas de sens.

Se référer à Go comme art antérieur est quelque peu ridicule.

Utilisation du terme Rob Pike et Ken Thompson utilisé lors de la création d'Utf-8 https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt

Rob Pike travaille maintenant sur Go, c'est pourquoi il utilise le terme d'origine.

Go et Rob Pike sont relativement nouveaux sur ce sujet. En fait, leur opinion est quelque peu hors de propos en termes de définition de ce qu'est une rune historiquement et dans la littérature populaire et la société. Rob n'a pas lui-même martelé de pierres runiques à la main, il a donc peu de qualifications pour définir ce qu'est une rune. Je parie qu'il ne peut même pas écrire ou lire lui-même un script runique, mais c'est ma supposition. Au mieux, il peut capturer ce concept par encodage, mais il ne peut pas entrer et dire qu'un caractère chinois, une écriture arabe ou un Hangul ou un visage souriant est une rune ou quoi que ce soit d'autre qui est un "Point de code" est maintenant aussi une Rune, ou quelque chose comme ça. Il semble presque piétiner de manière irrespectueuse le terme, regardez, maintenant tout peut être une rune, ce qui signifie que les runes ne sont rien d'autre qu'un terme générique de quatre lettres pour désigner quelque chose d'ésotérique dans le domaine de l'encodage de texte.

Rune est un type spécifique de glyphe qui est ironiquement défini par Unicode.

Runic est défini par Unicode, Rune n'est pas

Unicode n'est pas censé redéfinir ce qu'est une rune ou un runique. S'ils le font, ils outrepassent leur mandat. Ils n'ont pas à dire au public ce qu'est une rune. En fait, ils n'ont rien à faire pour définir une nouvelle langue ou un nouveau système de caractères. Ils ne peuvent pas se contenter de s'approprier un mot qui est déjà un terme clairement surchargé depuis mille ans et ensuite courir en l'acclamant comme s'ils avaient inventé un nouveau concept. L'écriture runique se compose uniquement de runes, et les runes sont déjà un concept établi. Si vous demandez à une personne au hasard dans une rue ce qu'est une rune, elle ne pensera pas à Unicode.

En plus de tous les problèmes ci-dessus, la rune est une mauvaise métaphore qui est la pire partie. Cela ne précise rien. Cela ajoute juste un autre niveau de confusion. Tout nouveau venu sur le sujet doit maintenant passer par une série d'explications et de lectures de désambiguïsation, car tout le monde arrive avec le contexte selon lequel une rune est un système d'écriture historique utilisé dans certaines cultures. L'explication devra ressembler à ceci : "Une rune est un point de code Unicode". "Mais pourquoi ne pas l'appeler point de code?" "Eh bien, parce que c'est trop long.", ou "Quelqu'un a décidé qu'il aime la rune". Donc, fondamentalement, parce que quelqu'un pense que 9 lettres, c'est trop par rapport à 4 (même s'ils ont une saisie semi-automatique avec Intellisense et ce n'est rien comparé au Java Kingdom Of Nouns), maintenant nous devons faire face à cette confusion et l'expliquer à des milliers de développeurs qui pourraient avoir besoin de se familiariser avec Unicode. Utilisez simplement une instruction using pour raccourcir le terme si vous l'utilisez beaucoup dans le code.

Il n'est pas non plus nécessaire que ce soit UnicodeCodePoint, cela peut simplement être CodePoint. C'est déjà unique. Il existe de nombreux termes d'API plus longs que "CodePoint", cela devrait donc suffire. Si c'est encore trop long, utilisez simplement une instruction using avec une abréviation.

Je prévois que cela deviendra l'une de ces questions d'entrevue qui n'ajoutent vraiment pas beaucoup de valeur ou qui ont une base logique dans quoi que ce soit d'utile. Au moins pour la métaphore "jalon", alors que nous sommes sur le sujet des mots symboliques utilisés dans le développement de logiciels basés sur des concepts dérivés de la pierre et de la roche, un jalon a une véritable signification descriptive. Il communique immédiatement un concept que tout le monde connaît. Aha, un jalon, comme quand on fait un long voyage et qu'on passe sur le sentier. C'est une belle métaphore du monde réel qui aide réellement à visualiser quelque chose et peut devenir instantanément un langage de gestion. Je ne peux pas imaginer que les gens parlent de runes de cette manière à moins qu'ils ne connaissent intimement le sujet, auquel cas ils sauront déjà que ce n'est qu'un terme gimmick pour le point de code.

Un meilleur mot est glyphe, car il représente déjà le concept général d'un symbole élémentaire en typographie.

Le problème est que "Glyphe" est un terme utilisé lors du rendu de l'unicode en texte visible (de : utf8everywhere.org)

Ce raisonnement ne prend pas non plus en charge la rune, car "rune" est un terme utilisé depuis plus de mille ans à travers l'histoire, bien avant qu'Unicode, les transistors, Microsoft ou l'open source n'existent.

Ce que je voulais dire, c'est que le mot "glyphe" est problématique car il est déjà utilisé comme l'un des concepts de rendu du texte ; c'est la représentation graphique de ce caractère dans une police particulière. Ainsi, un caractère peut être représenté par de nombreux glyphes différents.

... encore une fois avec @benaadams ayant la vue à 10 000 mètres des choses et la bonne réponse 😁

Honnêtement, nous allons devoir vivre avec le vieil adage : « vous pouvez rendre certaines personnes heureuses tout le temps, et toutes les personnes heureuses une partie du temps ; mais vous ne pouvez pas rendre toutes les personnes heureuses toutes le temps." C'est vraiment une situation de l'ancien.

Sceau ?

Exit, pursued by a bear.

En tant que personne qui utiliserait cette API de manière intensive, je vote fortement pour le point de code. La terminologie Unicode est déjà suffisamment déroutante et les incohérences abondent déjà. Vous me rendrez la vie beaucoup plus facile si je peux juste dire "point de code" partout.

Je suis allongé dans mon lit en ce moment. Si je me tourne de côté, je fais face à un tableau blanc appuyé contre mon mur. Pendant des mois, ce tableau blanc a abrité divers gribouillis et graphiques pendant que j'essayais de comprendre comment gérer efficacement les IDN en C#. Je le traite comme une relique que j'ai invoquée des profondeurs de l'enfer. Si j'essayais d'expliquer la logique qu'il décrit, je n'en serais pas capable.

S'il vous plait, ne me compliquez pas la vie. Un point de code est un point de code. Ce n'est pas une rune, un glyphe, un caractère, un graphème ou même un symbole. Il n'a pas besoin de représenter quoi que ce soit de significatif pour un humain - il pourrait s'agir d'un code de contrôle. Cela pourrait ne pas représenter un symbole visuel, comme le nom "rune" l'indique. C'est juste un point de code.

Un argument plus concret est que «rune» implique la représentation d'un seul graphème, ce qui n'est très souvent pas le cas. Si je compte le nombre de points de code et le nombre de graphèmes, j'obtiendrai peut-être deux nombres très différents. La même séquence de graphèmes pourrait être représentée par deux séries distinctes de points de code.

Un meilleur mot est glyphe, car il représente déjà le concept général d'un symbole élémentaire en typographie.

C'est encore pire. Un seul point de code peut être représenté par plusieurs glyphes, et un seul glyphe peut représenter plusieurs points de code. Le mappage exact peut varier selon le système, le programme, la police de caractères...

Tous ces mots ont des significations techniques bien précises. Si les différences peuvent sembler insignifiantes dans le cadre de cette proposition, elles ont de réelles conséquences ailleurs, notamment dans les langues autres que l'anglais.

Juste pour illustrer à quel point il peut être difficile de traiter un texte, même dans une langue aussi courante que l'allemand :

  1. Convertissez ß en majuscules et vous obtiendrez SS .
  2. Reconvertissez-le en minuscules et vous obtiendrez ss .

Problèmes:

  • Que doit retourner char.ToUpper('ß') ? (Il doit retourner un seul caractère.)
  • Une version majuscule de ß que mon téléphone ne peut pas entrer dans cette zone de texte a été ajoutée à Unicode 5.1. Si j'essaie de le coller, j'obtiens SS. Désormais, les conversions supérieur/inférieur sont encore plus ambiguës.
  • Changer la casse d'une corde modifie sa longueur.
  • Les changements de cas ne sont pas idempotents ou réversibles.
  • Vous ne pouvez pas effectuer une comparaison insensible à la casse en mettant simplement en minuscule chaque chaîne.

Même s'il ne s'agit pas d'un exemple direct d'une situation dans laquelle la terminologie cause des problèmes, cela montre qu'il existe des sortes de cas extrêmes auxquels nous ne pensons normalement pas. Donner à chaque terme une signification distincte et cohérente aide les programmeurs à communiquer ces problèmes. Si je demande à un coéquipier d'écrire une fonction pour compter les graphèmes, il sait exactement ce qu'il va compter et comment le faire. Si je leur demande de compter les points de code, encore une fois, ils savent exactement quoi faire. Ces définitions sont indépendantes des langages et des technologies que nous utilisons.

Si je demande à un développeur JavaScript de compter les runes, il va me regarder comme si j'avais trois têtes.

Wikipédia dit

Unicode définit un espace de code de 1 114 112 points de code dans la plage 0hex à 10FFFFhex

Le point de code semble être le nom officiel. J'ai lu ce fil et je n'ai pas trouvé d'argument de forçage pour expliquer pourquoi le point de code serait incorrect.

Je suis d'accord que le point de code n'est pas le terme correct à utiliser ici. À tout le moins, selon la norme Unicode, il n'inclut pas les valeurs supérieures à 10FFFF (http://unicode.org/glossary/#code_point).

Peut-être que cette phrase est juste fausse ? Il dit "n'importe quelle valeur dans l'espace de code". Donc, cela signifie clairement tout tout en se trompant sur le nombre entier.

De plus, "rune" a une signification réelle qui n'a rien à voir avec Unicode. En Allemagne, le mot "Rune" a des connotations nazies car les runes ont une histoire "germanique" à laquelle les nazis aimaient se référer.

Je trouve que "rune" est un nom déroutant. Est-ce que quelqu'un ici aime vraiment "rune" ou ses arguments sont-ils basés sur l'exactitude. Intuitivement, c'est un très mauvais nom.

Peut-être que cette phrase est juste fausse ? Il dit "n'importe quelle valeur dans l'espace de code". Donc, cela signifie clairement tout tout en se trompant sur le nombre entier.

Cette phrase est correcte. L'espace de code va de U+0000 à U+10FFFF. Unicode pourrait théoriquement être étendu au-delà de cela un jour, mais cela casserait UTF-8 et UTF-16. Nous aurions besoin de nouveaux encodages.

Edit: En fait, ne me citez pas sur la rupture UTF-16, mais je suis presque sûr que cela cassera UTF-8. UTF-8 ne peut certainement pas représenter 0xFFFFFF (2^24 -1).

Edit 2 : Pour clarifier, Unicode indique que les points de code ne peuvent jamais dépasser U+10FFFF. Cela ne signifie pas qu'il existe actuellement 0x110000 points de code - la plupart de ces points de code ne sont pas attribués.

@Zenexer @GSPP

Ce type tel qu'il est actuellement enregistré dans master ( System.Text.Rune ) correspond très spécifiquement à une "valeur scalaire Unicode" ( voir glossaire ). Les ctors du type lèveront une exception si vous essayez de le construire à partir des valeurs -1 , 0xD800 ou 0x110000 , car ce ne sont pas des valeurs scalaires selon la spécification Unicode. Si vous prenez un paramètre Rune comme entrée dans votre méthode, vous n'avez pas à effectuer de contrôle de validation dessus. Le système de type s'est déjà assuré qu'il a été construit à partir d'une valeur scalaire valide.

Re : conversion de casse, toutes les API de conversion de casse du .NET Framework _sauf indication contraire_ utilisent une technique appelée pliage de casse simple. Selon les règles de pliage de casse simple, pour toute valeur scalaire d'entrée, les formes de sortie minuscules, majuscules et de titre sont également garanties chacune comme étant exactement une valeur scalaire. (Certaines entrées, comme les chiffres 0-9 ou les symboles de ponctuation, n'ont pas d'entrées dans la carte de conversion de casse. Dans ces cas, des opérations comme _ToUpper_ renvoient simplement la valeur scalaire d'entrée.) De plus, sous des règles de pliage de casse simples si l'entrée est dans le plan multilingue de base (BMP), la sortie doit également être dans le BMP ; et si l'entrée est dans un plan supplémentaire, la sortie doit également être dans un plan supplémentaire.

Il y a des conséquences à cela. Tout d'abord, Rune.ToUpper et ses amis renverront toujours une seule valeur _Rune_ (scalaire). Deuxièmement, String.ToUpper et ses amis renverront toujours une chaîne avec exactement la même longueur que son entrée. Cela signifie qu'une chaîne contenant 'ß' (minuscule eszett), après une opération de conversion de casse, peut finir par contenir 'ß' (pas de changement) ou 'ẞ' (majuscule eszett), selon la culture utilisée. Mais il _ne contiendra pas_ "SS", car cela modifierait la longueur de la chaîne, et presque toutes les API de conversion de casse .NET exposées publiquement utilisent des règles de pliage de casse simples. Troisièmement, Utf8String.ToUpper et ses amis (pas encore enregistrés) ne sont _pas_ assurés de renvoyer une valeur dont la propriété _Length_ correspond à la propriété _Length_ de la valeur d'entrée. (Le nombre d'unités de code UTF-16 dans une chaîne ne peut pas changer après un simple pliage de casse, mais le nombre d'unités de code UTF-8 dans une chaîne peut changer. Cela est dû à la façon dont les valeurs BMP sont codées par UTF-16 et UTF- 8.)

Certaines API .NET utilisent en interne des règles de pliage de casse complexes plutôt que des règles de pliage de casse simples. String.Equals , String.IndexOf , String.Contains et des opérations similaires utilisent des règles complexes de pliage de casse sous les couvertures, selon la culture. Ainsi, si votre culture est définie sur _de-DE_, la chaîne à un caractère "ß" et la chaîne à deux caractères "SS" seront comparées comme égales si vous transmettez _CurrentCultureIgnoreCase_.

@GrabYourPitchforks Je m'oppose principalement au choix du nom. L'exemple de casier était purement pour souligner à quel point Unicode (et le texte en général) peut être compliqué. Tant qu'il existe un moyen de gérer la normalisation , je me fiche de la façon dont les opérations simples fonctionnent, car je vais de toute façon convertir en NFKD pour tout pour mon cas d'utilisation.

Cette phrase est correcte. L'espace de code va de U+0000 à U+10FFFF. Unicode pourrait théoriquement être étendu au-delà de cela un jour, mais cela casserait UTF-8 et UTF-16. Nous aurions besoin de nouveaux encodages.

Juste pour être pinailleur (ou, si les gens sont intéressés) : en théorie, l'algorithme UTF-8 fonctionne jusqu'à 42 bits (préfixe octet 0xFF et 7 octets de charge utile de 6 bits), et à l'origine, les premières spécifications couvraient les 31 bits complets. l'espace binaire de ces anciennes versions du jeu de caractères universel (UCS4) - cependant, les spécifications actuelles (RFC 3629, norme Unicode, annexe D de l'ISO/CEI 10646) conviennent toutes de le restreindre à la plage actuelle de points de code valides (U+ 0000 à U+10FFFF).

Pour UTF-16, la situation est plus difficile. Mais ils pourraient réserver des points de code dans un plan supérieur comme "Escapes" pour 32 bits ou plus. Les plans 3 à 13 étant actuellement indéfinis, ils pourraient en réserver deux comme "plan de substitution bas" et "plan de substitution haut". Ensuite, un point de code de 32 bits serait divisé en deux valeurs de 16 bits (une dans chaque plan), puis chaque valeur serait codée à l'aide de deux substituts "classiques", en utilisant effectivement 4 unités de code de 16 bits chacune pour coder un point de code de 32 bits.

Au fait, AFAICS, le consortium Unicode a déclaré publiquement qu'il n'allouerait jamais de points de code au-dessus de U + 10FFFF, donc en pratique, j'espère que je serai longtemps à la retraite avant que cela ne se produise. :clin d'œil:

Ce type tel qu'il est actuellement archivé dans master ( System.Text.Rune ) correspond très spécifiquement à une "valeur scalaire Unicode"

@GrabYourPitchforks merci pour cette clarification. Cela signifie que la structure ne représente pas un point de code. Donc, ce nom serait en effet incorrect.

Je suppose que UnicodeScalar est trop mystérieux comme nom...

@GrabYourPitchforks , que reste-t-il à faire pour ce problème ?

@stephentoub Il n'y a pas de fonctionnalité supplémentaire prévue pour le type Rune dans la boîte pour 3.0, mais @migueldeicaza avait des idées pour étendre la portée du type, y compris pour des choses comme les grappes de graphèmes. (La chose la plus proche que nous ayons dans la boîte est TextElementEnumerator , qui est un type très obsolète.) Certaines de ces idées ont été évoquées dans ce fil, mais il n'y a encore rien de concret.

Nous pourrions laisser ce problème ouvert au cas où la communauté souhaiterait discuter davantage des scénarios, ou nous pourrions demander aux gens d'ouvrir de nouveaux problèmes s'ils souhaitent faire des suggestions spécifiques. TBH Je n'ai pas de préférence marquée.

Merci. Étant donné que Rune a déjà été introduit et que les API décrites ici (ou leurs approximations) sont déjà exposées, fermons cela. Une assistance supplémentaire peut être traitée via des problèmes distincts.

Alors est-ce essentiellement stabilisé à ce stade? Parce qu'en toute honnêteté, ce nom épouvantable, qui ne correspond à aucune information que vous trouverez sur Unicode provenant de sources bonnes et précises, et a la nuance malheureuse d'impliquer un glyphe par opposition à un caractère non imprimable, ne fera que aggraver la compréhension déjà terrible d'Unicode par votre programmeur moyen.

Je sais que cela a été intégré à ce stade, mais je veux juste intervenir sur la partie Rune et le désaccord de certaines personnes sur le nom.

J'ai rencontré Rune la première fois dans Plan 9, et comme d'autres l'ont vu dans Go et d'autres. Lorsque les msdocs ont commencé à répertorier Rune , je savais exactement ce que c'était avant de lire.

Dans au moins deux instances, Plan 9 et Go, les personnes responsables de l'UTF-8 utilisent le nom Rune . Je pense qu'il est prudent de dire qu'ils ont déjà pensé à ces préoccupations et qu'ils pensaient toujours que Rune était raisonnable. Runic n'est plus vraiment un système d'écriture utilisé, sauf chez certains traditionalistes. Et Rune signifie le graphème dans ce système, tout comme il signifie essentiellement le graphème ici (sauf dans des cas comme les caractères de contrôle.

Je vois vraiment peu de mal avec le nom. Runic est un système d'écriture si ancien que je doute fortement que votre programmeur moyen le confond, et il existe déjà une norme de facto vieille de plusieurs décennies de Rune pour les "caractères" Unicode appropriés.

@Entomy

tout comme cela signifie essentiellement le graphème ici (sauf dans des cas comme les caractères de contrôle.

Ce n'est tout simplement pas vrai. Unicode contient un grand nombre de points de code précomposés qui représentent plusieurs graphèmes (généralement des combinaisons de lettres et de signes diacritiques), et ceux-ci sont couramment utilisés pour écrire des langues telles que le français et l'espagnol, et à peu près tout le texte informatisé dans ces langues utilisera ce code. points.

Inversement, même lorsqu'un seul point de code représente un graphème, il est très courant qu'ils se combinent en un _grappe de graphèmes_, ce qui est essentiel pour la bonne gestion du texte dans la plupart des langues indiennes. Ainsi, un seul caractère tel que perçu par l'utilisateur lorsqu'il se déplace avec les touches fléchées correspond souvent à plusieurs points de code en séquence. Ainsi, il ne peut y avoir de correspondance facile entre les points de code et les graphèmes ou les groupes de graphèmes. Même "personnage" serait probablement un meilleur nom, étant donné que les programmeurs sont habitués à considérer les caractères bizarres et farfelus à ce stade, tandis que "rune" donne l'impression que le problème de déterminer les limites des caractères perçus par l'utilisateur a été résolu pour le programmeur déjà quand il n'a en fait pas été.

Lorsque les msdocs ont commencé à répertorier Rune, je savais exactement ce que c'était avant de lire.

Le fait que vous pensiez que le nom rune décrivait bien les graphèmes est une très bonne preuve du problème que j'ai ici : le nom "rune" donne aux programmeurs un faux sentiment de sécurité en facilitant la supposition qu'il existe une telle correspondance.

Dans au moins deux instances, Plan 9 et Go, les personnes responsables de l'UTF-8 utilisent le nom Rune .

Autant de respect que j'ai pour Ken Thompson et Rob Pike, leur travail ici consistait essentiellement à concevoir un schéma très intelligent pour coder une série d'entiers de longueur variable. Ils ne sont pas des experts sur Unicode dans son ensemble, et je ne suis pas du tout d'accord avec eux sur cette question. J'admets que je ne suis pas non plus un expert en Unicode, mais je ne pense pas que l'appel à l'autorité ici soit aussi fort qu'il y paraît.

et il existe déjà une norme de facto vieille de plusieurs décennies de Rune pour les "caractères" Unicode appropriés.

"Normal" vous dites ? Ce sont principalement ces deux-là qui ont poussé le nom, et quelques langages de programmation mineurs tels que Nim l'ont adopté à partir de Go. Et bien sûr, je dois répéter qu'un point de code ne représente pas un seul "caractère Unicode approprié", que ce soit dans le sens de la sélection, du mouvement des touches fléchées, des graphèmes ou des grappes de graphèmes.

...signifie essentiellement le graphème ici...

Oui, car ce n'est pas exactement mais à peu près assez proche. Les graphèmes, du moins tels qu'ils sont définis en linguistique, sont les composants orthographiques qui constituent un système d'écriture et sont utilisés pour exprimer des phonèmes. Ce n'est pas une chose 1: 1. Dans les syllabaires et les logosyllabaires, un seul graphème peut représenter plusieurs phonèmes, généralement une paire consonne-voyelle. À l'inverse, les langues alphabétiques ont souvent des cas de graphèmes multiples représentant un seul phonème, comme "th" en anglais étant responsable de l' eth et de l' épine archaïques , selon le mot spécifique. Ensuite, vous ne pouvez même pas trouver d'accord entre les langues pour savoir si une lettre comme 'á' est sa propre lettre unique, ou 'a' avec un accent. Nous ne pouvons même pas établir de cohérence dans des langues vieilles de milliers d'années. Nous n'allons pas avoir un ajout parfaitement cohérent en plus de cela, c'est-à-dire l'encodage de ceux-ci.

Puisque vous plaidez pour une sémantique extrêmement stricte, ce que UNICODE appelle un "grappe de graphèmes" n'est souvent en linguistique qu'un seul graphème. Est-ce UNICODE invalide ? Non. Cela signifie-t-il qu'UNICODE doit le renommer ? Non pourquoi? Parce que le contexte. Les champs ont leur propre jargon, et tant qu'il n'y a pas de confusion dans un seul champ, ce n'est pas un problème.

Je ne vois pas le nom comme trop important. Msdocs est clair sur ce que Rune est dans le résumé. Si les gens ne lisent pas les docs, c'est leur propre problème. Les gens ne réagissent pas avec véhémence à "Stream" et disent des bêtises comme "oh mais et si les gens pensent que c'est une petite rivière, parce qu'elle a déjà le même nom !" Non.

@Serentty @Entomy Vous pourriez également être intéressé par la classe StringInfo , qui expose le concept Unicode réel "grappes de graphèmes étendus". Le type StringInfo est assez ancien et implémente par conséquent une très ancienne version de la norme Unicode, mais il y a un travail actif pour le mettre à jour afin qu'il soit conforme à UAX #29, Sec.

Oui, car ce n'est pas exactement mais à peu près assez proche.

Je pense que la question des représentations composées versus décomposées rend cela faux. Si nous suivons la définition linguistique d'un graphème ici par opposition à toute sorte de définition liée à l'informatique, alors 한 et 한 sont exactement la même séquence de graphèmes (trois Hangul jamo représentant la syllabe _han_ comme les segments HAN), et pourtant, le premier n'est qu'un seul point de code alors que le second est une séquence de trois.

Les champs ont leur propre jargon, et tant qu'il n'y a pas de confusion dans un seul champ, ce n'est pas un problème.

C'est exactement mon point aussi. Unicode est un système vraiment compliqué avec sa propre terminologie, alors pourquoi essayer de lui imposer une sorte de terme «intuitif» à moitié cuit alors qu'il ne s'aligne pas aussi précisément? Les points de code sont des points de code. Ils n'ont pas de parallèle linguistique, et essayer d'être intuitif alors que seulement 75% de précision est une recette pour le même genre de catastrophe dont C # essaie toujours de se remettre.

Puisque vous plaidez pour une sémantique extrêmement stricte, ce que UNICODE appelle un "grappe de graphèmes" n'est souvent en linguistique qu'un seul graphème.

Dans la norme, un cluster est autorisé à ne comprendre qu'un seul graphème. Il n'y a rien de mal à cela ici. Un _cluster_ est une unité de sélection de texte et de déplacement du curseur.

Je ne vois pas le nom comme trop important. Msdocs est clair sur ce qu'est Rune dans le résumé. Si les gens ne lisent pas les docs, c'est leur propre problème.

C'est l'argument « les programmeurs doivent être plus intelligents » qui revient à plusieurs reprises pour défendre les mauvaises décisions de conception. Si les programmeurs ont besoin de lire la documentation et d'apprendre qu'une rune est de toute façon un point de code Unicode, alors à quoi bon l'appeler un nom plus «intuitif» en premier lieu? L'argument ici semble être que le "point de code" est déroutant, il est donc logique de choisir un nom plus intuitif, mais lorsqu'ils sont confrontés au problème du nom trompeur, la défense est que les programmeurs doivent savoir ce qu'est un point de code est de toute façon à partir de la lecture de la documentation. Si tel est le cas, pourquoi ne pas simplement appeler le type CodePoint et faciliter la recherche et l'apprentissage pour les programmeurs ? Tout cela met de côté le problème que la documentation .NET est assez terrible en ce qui concerne Unicode en premier lieu, traite les paires de substitution comme une réflexion après coup dans un monde de "caractères Unicode 16 bits".

C'est l'argument « les programmeurs doivent être plus intelligents » qui revient à plusieurs reprises pour défendre les mauvaises décisions de conception.

Je n'ai jamais dit cela.

L'argument ici semble être que le "point de code" prête à confusion

Je n'ai jamais dit ça non plus.

Les gens ne réagissent pas avec véhémence à "Stream" et disent des bêtises comme "oh mais et si les gens pensent que c'est une petite rivière, parce qu'elle a déjà le même nom !" Non.

Je dis que les programmeurs sont assez intelligents pour ne pas penser que Rune est spécifiquement une rune runique, de la même manière qu'ils savent que Stream n'est pas une petite rivière.

Permettez-moi de répéter ceci

Je dis que les programmeurs sont assez intelligents pour comprendre cela. Tu me mets des mots dans la bouche.

Je ne vois pas le nom comme trop important. Msdocs est clair sur ce qu'est Rune dans le résumé. Si les gens ne lisent pas les docs, c'est leur propre problème.

C'est à cela que je fais référence ici. L'argument en faveur du nom « rune » est basé sur l'intuition et le lien intuitif avec la notion de graphème. Vous disiez vous-même que les deux étaient suffisamment alignés pour que ce ne soit pas un problème. Lorsque j'ai souligné toutes les façons dont cette intuition était fausse et que la correspondance pouvait être très mauvaise, votre réponse a été essentiellement que cela n'avait pas d'importance parce que les programmeurs avaient besoin de lire la documentation de toute façon. C'est ce que je veux dire par "les programmeurs doivent être plus intelligents". La documentation n'est pas une excuse pour les noms trompeurs lorsqu'il n'y a aucune raison héritée pour eux.

Je dis que les programmeurs sont assez intelligents pour ne pas penser que Rune est spécifiquement une rune runique, de la même manière qu'ils savent que Stream n'est pas une petite rivière.

Mon argument ici n'est pas que les gens le confondront avec les runes runiques. Mon argument est que les gens le confondront avec les glyphes, les graphèmes et les grappes de graphèmes, qui, malgré votre insistance, sont tous très mal corrélés avec les points de code.

Je dis que les programmeurs sont assez intelligents pour comprendre cela. Tu me mets des mots dans la bouche.

Assez intelligent pour comprendre que ce ne sont pas de véritables runes germaniques, bien sûr. Mais pour comprendre qu'il ne s'agit pas de glyphes, de graphèmes ou d'amas de graphèmes ? Mon expérience réelle avec la qualité de la gestion d'Unicode par la plupart des logiciels dit que non.

Si les gens ne lisent pas les docs, c'est leur propre problème.

Oui, et je m'en tiens à cela. Pas par manque d'intelligence, mais plutôt par tendance à des suppositions hâtives.

Si un programmeur suppose que String signifie un morceau de corde solide et fin, fabriqué à partir de la torsion de fils, car, oui, cela signifie que cela n'est pas considéré comme un problème avec le nom String .

Si un programmeur suppose que Char signifie un matériau carbonisé tel que du charbon de bois ou un type particulier de truite, cela n'est pas considéré comme un problème avec le nom Char .

Si un programmeur suppose que character signifie la représentation d'un ensemble de traits mentaux et éthiques utilisés dans la narration, cela n'est pas considéré comme un problème avec le nom character .

Remarquez que ce ne sont que des questions textuelles/linguistiques. Ils ont tous d'autres significations. Et pourtant, les programmeurs se sont très bien acclimatés. Ces termes sont devenus des standards de facto, en raison d'une convention établie dans le domaine : notre jargon. Il existe un précédent établi selon lequel les programmeurs sont assez intelligents pour suivre cela.

Vous disiez vous-même que les deux étaient suffisamment alignés pour que ce ne soit pas un problème.

Oui, c'est GitHub. Sur un problème déjà clos, où je ne faisais qu'ajouter mes réflexions sur la raison pour laquelle je pensais que Rune était bien parce qu'il y avait un précédent établi dans le nom. Ce n'est ni le lieu ni le contexte pour écrire un traité, rempli de définitions détaillées et de mots soigneusement choisis. Par exemple, si je mets un PR pour, disons, un décodeur UTF-8, je ne vais pas décrire explicitement pourquoi j'ai implémenté le DFA Hoehrmann sur des approches alternatives. Je vais juste dire "ça y est, voici une preuve que cela fonctionne, voici quelques repères qui prouvent pourquoi j'ai opté pour ça".

Mon argument est que les gens le confondront avec les glyphes, les graphèmes et les grappes de graphèmes

Ils ne confondent aucun des éléments susmentionnés, ni Tree , Heap , Table , Key , Socket , Port ...

C'est un argument extrêmement hypocrite. Un morceau de fil et une chaîne de texte ne se confondent pas facilement. Une grande plante et une structure de données arborescente ne sont pas faciles à confondre. Un point de code, en revanche, est un concept très mal compris par la plupart des programmeurs et constamment confondu avec tous les autres concepts dont nous avons discuté. La solution à cela est, comme vous le dites, de lire la documentation. Cependant, un langage utilisant son propre nom "intelligent" pour les points de code rend encore plus difficile l'application des connaissances de la _documentation Unicode réelle_ à ce langage. Et cela m'amène à ceci :

Ces termes sont devenus des standards de facto, en raison d'une convention établie dans le domaine : notre jargon.

Et c'est le nœud de tout. Vous semblez affirmer que "rune" est un terme bien établi pour un point de code largement compris dans la programmation, ou qu'il devrait l'être. Si c'est le premier, alors je vous invite à demander à un programmeur moyen expérimenté dans un langage de programmation majeur autre que Go s'il l'a déjà entendu. Si c'est ce dernier, alors je vous demanderais l'intérêt de rivaliser avec la terminologie officielle Unicode dans une situation déjà confuse et mal comprise qui est souvent mal comprise, même par des développeurs très expérimentés.

@Entomy outsider input: tout votre argument, pour autant que je sache, est "c'est déroutant et mauvais, oui, mais ce n'est pas si déroutant et mauvais".
Alors? Pourquoi ne peut-il pas être réellement bon à la place ? Quel est le problème de le nommer exactement comme Unicode le nomme ?
De plus, les runes ne sont pas des points de code, ni même des graphèmes ou des clusters, dans le domaine général de l'informatique. Si vous recherchez "runes Unicode" dans Google, tout ce qui les relie aux points de code n'apparaît qu'à la page 2, et même dans ce cas, il ne s'agit que de liens godoc / Nim. Même sur DuckDuckGo, avec lequel les programmeurs pourraient être plus à l'aise, c'est toujours un résultat de page 2. Donc, le seul argument qui reste pour le nom que j'ai vu est qu'il est intuitif qu'il représente un point de code, mais ce n'est pas . Il est intuitif qu'il représente un groupe de graphèmes, ou peut-être juste un graphème.
Source : J'ai utilisé Go et je pensais que c'était un graphème jusqu'à quatre ans plus tard, lorsque j'ai lu ce numéro tout à l'heure.

(et dire que c'est bien qu'il suggère un graphème parce qu'il est "assez proche" me rappelle que le caractère 16 bits est assez proche.)
Oui, si les programmeurs étaient plus intelligents et lisaient plus de documentation, nous n'aurions pas besoin d'un nom significatif pour cela, ni même d'un type du tout. Les gens sauraient simplement qu'il faut passer des points de code dans un int au lieu de char. Mais ils ne le sont pas. Ils sont aussi intelligents qu'ils le sont en ce moment, et cela ne va pas changer simplement parce que Yet Another API a été ajouté. L'objectif est d' augmenter la quantité de logiciels qui gèrent correctement les langues autres que l'anglais, pas seulement d'introduire de nouvelles façons de faire la même chose et de maintenir les mêmes barrières à l'entrée qu'auparavant.

Juste pour les besoins de la discussion, et à des fins scientifiques, j'aimerais pointer tout le monde ici vers le langage de programmation qui gère le mieux le texte Unicode, où "le meilleur" est défini par "le plus proche conformément à la norme Unicode", et non en feignant la simplicité : Swift

  • String est un tampon de texte Unicode arbitraire.
  • Character , sur lequel vous parcourez ou non, n'est pas une seule valeur scalaire Unicode, mais un cluster de graphème étendu. Voir cet exemple pour le cluster de graphèmes  : let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
  • Si vous avez besoin de valeurs scalaires Unicode, vous pouvez également les parcourir. Leur type est appelé UnicodeScalar .
  • Et si vous en avez vraiment vraiment besoin, vous pouvez également parcourir les unités de code UTF-8 et UTF-16, ce qui donne UInt 8 s et UInt 16 s.

Maintenant, je ne suggère pas ici que C # adopte le style Swift complet. Bien que ce soit incroyable, c'est aussi beaucoup de changements et de travail nécessaires. Je suis ici pour suggérer de choisir la dénomination de style Swift, cependant, pour toutes les raisons soulignées par @Serentty , et de laisser l'option ouverte pour transformer éventuellement les chaînes de texte en style Swift.

Quelques meilleurs noms potentiels que Rune : CodeUnit32 , UnicodeScalar , CodeUnit , UniScalar , UnicodeValue , UniValue , UnicodeScalarValue . Je pense que les deux premiers pourraient parfaitement s'intégrer dans les conventions de dénomination de C#. Notez que UnicodeScalar est objectivement le meilleur nom, car les unités de code ne sont que des moyens d'encoder une valeur scalaire Unicode dans le jargon Unicode. Ainsi, CodeUnit32 implique une itération sur les unités de code d'une chaîne de texte encodée en UTF-32, alors que UnicodeScalar est indépendant de l'encodage.

Edit : Oui, le nom System.Rune existe déjà. Tout cela n'est qu'un "si nous voulons l'améliorer avant que cette chose n'ait une demi-décennie".

@saveur de tarte

tout votre argument, pour autant que je sache, est "c'est déroutant et mauvais, oui, mais ce n'est pas si déroutant et mauvais".

Non ce n'est pas du tout mon argument. Je fais de mon mieux avec mon handicap, mais ce n'est pas mon intention de communication.

Si vous recherchez "runes Unicode" dans Google, tout ce qui les relie aux points de code n'apparaît qu'à la page 2, et même dans ce cas, il ne s'agit que de liens godoc / Nim.

Si vous recherchez "chaîne Unicode" dans Google, vous n'obtiendrez pas non plus spécifiquement le fonctionnement des chaînes .NET. Il s'agit de rechercher une chose adjacente. Par analogie très stricte, je programme à la fois en .NET et en Ada ; string n'est pas le même entre eux, et une légère lecture pour chacun est une bonne idée.

Les définitions surchargées ne sont pas inhabituelles dans la langue, et pourtant nous nous débrouillons très bien. Cela pourrait vous surprendre, mais "run" a au moins 179 définitions formelles, "take" en a au moins 127, "break" en a au moins "123", et ainsi de suite. [ source ] Les gens sont incroyablement capables et peuvent naviguer avec succès dans bien plus de complexité que ce qui est considéré comme problématique ici. La préoccupation de "rune" ayant au moins 2 définitions formelles n'est, à mon avis, pas justifiée lorsqu'il est démontré que les gens gèrent plus de 50 fois les surcharges.

De plus, cela exploite grossièrement le comportement des moteurs de recherche. Avec la plupart des moteurs de recherche, vous obtenez des résultats basés sur le nombre de pages liées à quelque chose. Il existe également d'autres facteurs, chaque approche pondérant les choses différemment. Comme .NET Rune est un concept assez récent en comparaison, il y aura beaucoup moins de contenu qui en parle et il faudra plus de pages pour y accéder. Mais c'est aussi utiliser le mauvais outil de recherche. Si je veux trouver des recherches sur les algorithmes de recherche de chaînes, pour voir si quelque chose de nouveau est apparu au cours des dernières années, je ne recherche pas Google ou DDG. Semantic Scholar, Google Scholar et d'autres sont de meilleurs points de départ. De même, si vous voulez comprendre des choses sur les API .NET, vous devez d'abord rechercher MSDocs. Si je me plains que "moment d'inertie", un terme de physique/ingénierie, est vague ou trompeur dans son nom, et qu'il devrait être renommé car je ne trouve aucune information à ce sujet dans les premiers livres, en commençant par le numéro le plus bas dans une bibliothèque utilisant la classification décimale Dewey, ce n'est pas un problème avec la dénomination du "moment d'inertie" ; Je cherche clairement au mauvais endroit.

Source : J'ai utilisé Go et je pensais que c'était un graphème jusqu'à quatre ans plus tard, lorsque j'ai lu ce numéro tout à l'heure.

J'ai parcouru les documents Go et les notes de version, du moins ceux que j'ai pu trouver, et je suis d'accord avec vous. Ils sont très vagues sur ce qu'est rune , et malheureusement même sur la taille rune . Je soupçonne que cette imprécision causera des problèmes plus tard, car j'ai vu Ada être tout aussi vague sur les contraintes de type de données et se mordre le cul des années plus tard.

Cependant, je dois dire que msdocs fait un bien meilleur travail avec une description très détaillée et concise.

Représente une valeur scalaire Unicode ([ U+0000..U+D7FF ], inclus ; ou [ U+E000..U+10FFFF ], inclus).

Cela étant dit, les remarques manquent quelque peu et quelques précisions sur la raison pour laquelle Rune existe et quand vous voudriez l'utiliser seraient bénéfiques (et aussi l'endroit approprié pour une explication plus détaillée que celle simplifiée susmentionnée) . J'y proposerai quelques améliorations.

@Evrey

Juste pour les besoins de la discussion et à des fins scientifiques, j'aimerais signaler à tout le monde ici le langage de programmation qui gère le mieux le texte Unicode

Ceci est un avis. Un avec lequel je suis absolument d'accord ; Swift gère certainement mieux l'UNICODE moderne. Mais sans une citation de recherche reproductible évaluée par des pairs confirmant ces résultats, ce n'est pas une affirmation scientifique.

Maintenant, je ne suggère pas ici que C # adopte le style Swift complet. Bien que ce soit incroyable, c'est aussi beaucoup de changements et de travail nécessaires.

Et casserait les logiciels existants.

laissez l'option ouverte pour transformer éventuellement les chaînes de texte en style Swift.

Et casserait les logiciels existants.

Oui, le nom System.Rune existe déjà. Tout cela n'est qu'un "si nous voulons l'améliorer avant que cette chose n'ait une demi-décennie".

Et casserait les logiciels existants.

À titre hypothétique, si des modifications devaient être apportées au nom existant, comment proposez-vous un logiciel existant ciblant .NET Core 3.0/3.1, où Rune est déjà utilisé, toujours compatible, tout en le faisant exister en tant que un nom différent dans les runtimes cibles ultérieurs ?

Et casserait les logiciels existants.

Comme mentionné, je ne fais que discuter du point de vue du principe et de l'idéalisme. La réalité des choses a été abondamment évoquée. Bien qu'il y ait une nuance à tout cela:

  • Adopter le style Swift avec des chaînes ne casse pas nécessairement le logiciel. Il s'agit simplement d'ajouter plus de méthodes et de types d'énumération en plus de l'interface String déjà existante. Je ne veux pas dire des choses radicales comme changer System.Char en un type de cluster graphème ou quelque chose du genre par là.
  • Si un nom de type existant comme System.Char était réutilisé pour un type différent, alors oui, ce serait un énorme changement de rupture. Et un changement irresponsable à cela. Je suis avec toi là-bas.
  • Un hypothétique .NET Core 4.0, parlant en SemVer, peut faire tout ce qu'il veut. En dehors de cela, les changements jusqu'à un hypothétique 4.0 ne sont pas si effrayants : transformez System.Rune en un alias de type obsolète pour System.UnicodeScalar ou quel que soit le nom. Les logiciels utilisant Rune ne remarqueront aucune différence, à part une note de dépréciation, et les nouveaux logiciels peuvent utiliser le type réel mieux nommé. Et un hypothétique 4.0 laisse alors tomber Rune .
  • De même, System.Char pourrait être transformé en un alias pour System.CodeUnit16 ou quelque chose du genre.
  • Le faire à la manière de Swift signifie alors simplement ajouter System.GraphemeCluster dans le mélange.
  • L'introduction de plus de nouveaux alias de mots clés pour tous ces types peut être problématique.

Il suffit de laisser tomber matière à réflexion ici. Je pense que System.Rune , bien qu'un mauvais nom de type pour son objectif, n'aggrave pas vraiment le statu quo de dénomination précédent. Je pense que c'est formidable qu'il existe enfin un type approprié capable d'encoder tous les scalaires Unicode. Cependant, je vois une belle opportunité de diffuser une tendance à une gestion et une dénomination Unicode plus précises. Une opportunité que chacun ici est libre de laisser de côté.

Salut à tous - le nom System.Text.Rune est ce qui a été expédié et ce que nous utilisons à l'avenir. Il y a eu une discussion importante (et passionnée !) Plus tôt sur l'utilisation du nom UnicodeScalar au lieu de Rune , mais à la fin, Rune l'a emporté. L'équipe n'a pas l'idée de lui choisir un nom différent pour le moment. Et bien que je sache que les gens sont passionnés par cela et que nous continuerons à surveiller la conversation ici, sachez en fin de compte que toute énergie dépensée à poursuivre le litige sur la question de la dénomination ne rapportera pas de dividendes.

Pour plus de clarté, et selon la documentation : le type System.Text.Rune dans .NET est exactement équivalent à une valeur scalaire Unicode. Ceci est imposé par la construction. Cela le rend plus analogue au type UnicodeScalar de Swift qu'au type rune de Go.

Un effort est en cours pour ajouter une section à la documentation Rune détaillant ses cas d'utilisation et son lien avec d'autres API de traitement de texte dans .NET et des concepts dans Unicode. Le problème de suivi est sur https://github.com/dotnet/docs/issues/15845. Il existe également un lien entre ce problème de suivi et une version actuelle de la documentation conceptuelle.

Pour moi, le principal inconvénient de UnicodeScalar est la grande disparité entre la longueur du nom du type et la taille des données du type. Il s'agit essentiellement d'un int avec quelques lacunes dans son domaine.

Cependant, la verbosité de l'utilisation serait extrême :

foreach (UnicodeScalar unicodeScalar in name.EnumerateUnicodeScalars())
{
     // ... unicodeScalar contains 1 int
}

vs l'équivalent char sur un string (et idéalement, les gens utiliseraient le nouveau type sur char car ce sont des valeurs entières plutôt que de contenir des valeurs fractionnées)

foreach (char c in name)
{
     // ... c contains 1 ushort
}

Rune est un compromis dans la verbosité du nom de type :

foreach (Rune rune in name.EnumerateRunes())
{
     // ... rune contains 1 int
}

@GrabYourPitchforks

Bonjour! Pour être honnête, j'ai été pris dans cet argument non pas parce que j'essaie de convaincre les gens de .NET que le nom doit être changé, car il semble que ce navire ait navigué, mais simplement parce que je voulais exprimer mon opinion à d'autres dans ce fil qui n'étaient pas d'accord avec cela. Je pense que c'est merveilleux que C # ait enfin un type de caractère _real_ par opposition au type de caractère cassé qu'il a eu pendant si longtemps, et le nom est complètement secondaire par rapport à cela. Je comprends qu'il y a un énorme équilibre à trouver entre la brièveté et la précision, et bien que j'aurais placé le sweet spot quelque part autour CodePoint , je comprends pourquoi les autres seraient en désaccord.

Mais encore une fois, je tiens à vous remercier pour tout le travail acharné dans la modernisation du support Unicode de .NET ! C'est quelque chose qui fait une énorme différence pour beaucoup de gens dans le monde.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

chunseoklee picture chunseoklee  ·  3Commentaires

bencz picture bencz  ·  3Commentaires

jkotas picture jkotas  ·  3Commentaires

omariom picture omariom  ·  3Commentaires

yahorsi picture yahorsi  ·  3Commentaires