ここでの議論に触発されました:
https://github.com/dotnet/corefxlab/issues/1751
.NETがUnicodeサポートで直面する課題の1つは、現在では廃止されている設計に根ざしていることです。 .NETで文字を表現する方法は、16ビット値であるSystem.Char
を使用することです。これは、Unicode値を表現するには不十分です。
.NET開発者は、難解なサロゲートペアについて学ぶ必要があります。
https://msdn.microsoft.com/en-us/library/xcwwfbb8(v = vs.110).aspx
開発者がこのサポートを使用することはめったにありません。これは主に、Unicodeに精通していないためであり、.NETが提供するものは言うまでもありません。
32ビット整数に裏打ちされたcodePointに対応するSystem.Rune
を導入し、C#で同等のrune
タイプをこのタイプのエイリアスとして表示することを提案します。
rune
は、 char
の推奨される代替品になり、.NETでの適切なUnicodeおよび文字列処理の基盤として機能します。
ルーンという名前の理由については、Goからインスピレーションを得ています。
https://blog.golang.org/strings
「コードポイント、文字、およびルーン」のセクションで説明が提供されます。短いバージョンは次のとおりです。
「コードポイント」は少し一口なので、Goは概念の短い用語であるルーンを導入します。 この用語はライブラリとソースコードに表示され、「コードポイント」とまったく同じ意味ですが、興味深い点が1つ追加されています。
更新私は今ここにSystem.Rune
の実装を持っています:
https://github.com/migueldeicaza/NStack/blob/master/NStack/unicode/Rune.cs
次のAPIを使用します。
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
}
}
既知の問題を更新する
インメモリ表現が32ビットオブジェクトの文字列であるか、またはその場で変換されることを期待しますか? 前者の場合、メモリの倍増はどうですか? 後者の場合、パフォーマンスにどのような影響がありますか?
Unicodeでサポートされている特定のスクリプト(およびBMPスクリプトの後のアストラル界のサポートを改善するテクノロジー)にちなんでUnicode関連のテクノロジーに名前を付けるのは良い考えですか?
文字列のメモリ内表現はまったく変更されないという提案(そしておそらくもっと明確にする必要がある)だと思います。 Rune
タイプは、個別の21ビットコードポイント(32ビットintとして格納)を表すだけです。 コードポイントを参照するメソッドは、代わりにRune
を返す可能性があります。 おそらく、 string
には、 Rune
を列挙できる機能がいくつかあります。
このようなことについてコンセンサスを得る必要がある明らかなポイントがいくつかあると思います。
Int32
を使用するのではなく、 Rune
タイプを作成することに大きな価値がありますか?(1)に答えるには、$# Int32
Rune
がどのように公開されるか、どのメソッドがそれを受け取り、返すかなどについて、より完全な説明が必要だと思います。代わりにInt32
。
(2)については、少し躊躇しています。 「ルーン」は英語の秘教的な言葉の一種であり、この文脈での使用にはいくつかの珍しい意味があります。 他の人が提起している点もあります。それは別のUnicodeの概念と衝突します。 「UnicodeRune」を検索すると、主にRunic Unicodeブロックの結果が表示され、Go言語のドキュメントはごくわずかです。
char
は、ハーフワードであると同時にフルワードでもあります。 そして、周囲を調べて、現在のように半分の文字を表しているのか、完全な文字を表しているのかを判断する必要があります。
おそらくSystem.character
ここでは常に完全な文字です...:サングラス:
char
は少しひどい表現であり、ASCII/ラテン語のみの言語でも同様です。 絵文字の台頭はまだ浸透します。 これは、 char
がチェックであり、次のchar
タイプをチェックする可能性があることを意味します
Twitterの@NickCraver
utf8は可変幅エンコーディングですが、 ユーザーが半分の文字を処理したいというのはまれです(あるとしても?)。 utf8とutf32の両方。
32ビットタイプは列挙に適しています。
より難しいのは、パフォーマンスまたはメモリの観点から、indexOf、Lengthなどです。
ただし、実際の文字、大文字、文字の分割を気にし始めると、 文字が何であるかを理解すると、バイトは可変幅になります。 Charはそれを本当に良くすることはありません。 最小の文字のサイズが2倍になります。 より多くの文字が含まれますが、それでも可変幅です。
このため、32ビット値はユーザーコードの観点から非常に役立つ場合があります。 ただし、位置、長さ、および2次項目(indexOfなど)に問題があります。
私はASCIIのみの文字列とutf8文字列「コンパクトな文字列の実装」に非常に熱心ですhttps://github.com/dotnet/coreclr/issues/7083; ASCIIのみの文字列を高速処理するため
しかし、そこで私が主張していたことすべてに反して... utf8の32ビット表現はどのようなものになるのだろうか? 位置は位置にマップされます。 文字の検索はASCIIの場合と同じように高速で、アイテムはネイティブサイズであるなど、すべてのバイトまたは文字を処理してサイズを決定するのとどのように重なりますか?
との間の変換はより高価になります。 したがって、それはより処理形式になります。 ストレージ形式よりも。
@migueldeicazaは、1文字の形式を16ビット文字から32ビットに拡張することだけを指しているので、すべての表現が値に含まれていることを理解しています。 半値の可能性ではなく、必ずしも内部形式ではありません。
ただし、考慮すべき点(つまり、位置の関係、シークのコストなど)
余談ですが、Swiftは文字全体の形式も扱っています
Swiftは、文字列のUnicode表現にアクセスするためのいくつかの異なる方法を提供します。 for-inステートメントを使用して文字列を反復処理し、Unicode拡張書記素クラスターとして個々の文字値にアクセスできます。 このプロセスについては、「文字の操作」で説明しています。
または、他の3つのUnicode準拠表現のいずれかで文字列値にアクセスします。
- UTF-8コードユニットのコレクション(文字列のutf8プロパティでアクセス)
- UTF-16コードユニットのコレクション(文字列のutf16プロパティでアクセス)
- 文字列のUTF-32エンコーディング形式(文字列のunicodeScalarsプロパティでアクセス)に相当する21ビットのUnicodeスカラー値のコレクション
元の号で言ったので、また言います。 フレーズが気に入らないために標準の言うことを放棄すると、解決する以上に混乱します。Unicodeにルーンコードページがあるとすると、それはさらに混乱します。
名前が間違っています。
@mellinoe
Runeは、ToLower [Invariant]、ToUpper [Invariant]、ToTitle、IsDigit、IsAlpha、IsGraphic、IsSymbol、IsControlなど、今日Charに期待される多くの操作を提供します。
さらに、次のようなものを提供します。
EncodeRune
(ルーンをバイトバッファにエンコードします)RuneUtf8Len
(UTF8でルーンをエンコードするために必要なバイト数を返します)、IsValid
(すべてのInt32値が有効であるとは限りません)そして、文字列への相互運用、および必要に応じてUtf8string。
Go文字列のサポートを.NETに移植/調整しました。これにより、この世界がどのように見えるかがわかります(これにはランタイムヘルプがありません)。
https://github.com/migueldeicaza/NStack/tree/master/NStack/unicode
@benaadamsは言った:
utf8の32ビット表現はどのようなものになるのでしょうか。 位置は位置にマップされます。 文字の検索はASCIIの場合と同じように高速で、アイテムはネイティブサイズであるなど、すべてのバイトまたは文字を処理してサイズを決定するのとどのように重なりますか?
UTF8はメモリ内の表現であり、引き続き存在し、表現であり続けます(そして、うまくいけば、これは.NETの将来の文字列の長期的な内部エンコーディングです)。
既存のUTF16文字列(System.String)または今後のUTF8文字列(Utf8String)をCharsではなく(あなたと私が同意する理由で)Runesにデコードします。
いくつかの例では、Utf8文字列をルーンに変換します。
utf8文字列にルーン文字が含まれていますか?
インデクサーを実装していないことに気づきました(「n番目のルーンを取得してください」)
文字列内のN番目のルーンへのアクセス速度は、ルーン自体ではなく、ストレージの関数です。 たとえば、ストレージがUTF32の場合、すべてのルーンに直接アクセスできます。 誰もそれを使用しないので、これは学術的です。 UTF16およびUTF8のN番目の要素にアクセスするには、文字列を構成する要素(バイトまたは16ビットint)を適切にスキャンして、正しい境界を決定する必要があります。 正確性に関係なく、n番目の文字を返すだけのString[int n] { get; }
と混同しないでください。
@benaadamsスウィフトキャラクターはルーンより上のレベルです。 swiftの文字は「拡張書記素クラスター」であり、1つまたは複数のルーン文字で構成されており、それらを組み合わせると人間が読める文字が生成されます。
したがって、Swift文字は固定の32ビットサイズではなく、可変長です(また、その構成も必要ですが、それは別のデータ型に属します)。 これがそのページの例ですが、これは絵文字の色合いの設定にも適用されます。
これが例です。 文字éは、単一のUnicodeスカラーé(LATIN SMALL LETTER E WITH ACUTE、またはU + 00E9)として表すことができます。 ただし、同じ文字をスカラーのペアとして表すこともできます。標準の文字e(LATIN SMALL LETTER E、またはU + 0065)の後に、COMBINING ACUTE ACCENTスカラー(U + 0301)が続きます。 COMBINING ACUTE ACCENTスカラーは、その前にあるスカラーにグラフィカルに適用され、Unicode対応のテキストレンダリングシステムによってレンダリングされるときにeをéに変換します。
私にとっては、 grapheme
という言葉の方が自己記述的です。
私の名前の2セントは、文字列に関するGoの投稿を強調して引用しています。
「コードポイント」は少し一口なので、Goは概念の短い用語であるルーンを導入します。 この用語はライブラリとソースコードに表示され、 「コードポイント」とまったく同じ意味ですが、興味深い点が1つ追加されています。
私は@blowdartに100%同意します。それをルーンと呼ぶのは混乱を招き、間違っています。 Unicode標準の言及コードは、導入の章の最初のページで3回ポイントしていますが、ルーンという用語はどこにも表示されません。
それがコードポイントである場合は、そのように単純なコードポイントという名前にする必要があります。
ルーンという用語が標準に表示されなかった場合、それは問題ない可能性があります。問題は、ルーンに関連して、第8章に数回表示されることです。 それは間違っているだけでなく、問題を他の問題と積極的に混同しています。
私にとっては、
grapheme
という言葉の方が自己記述的です。
これが約32ビットのコードポイントである場合、書記素はまた別のものであるため、 grapheme
という用語は混乱を招きます。
私はしばしばコードポイントデータ型を望んでいました(私が取り組んできたものが変わったので、しばらくはありませんが、数年前に私はこれをたくさん欲しがり、その必要性の一部に重複する部分的な解決策を書きました十分にテストされたライブラリで行うことができます)。 なぜこれをCodePoint
のような名前にすべきではないのかわかりません。 そのようなタイプが必要であることに気付いたほとんどの人は、ルーンではなく、とにかくコードポイントの観点から考えているでしょう。 または、コードポイントとルーンをタスクの個別の部分として使用します。 ᚱᚢᚾᚪᛒᛇᚦᛥᛁᛚᛖᛒᚱᚣᚳᛖᚢ/rúnabéoþstillebryceu/runesはまだ使用されています。 私は年に1回程度ルーンを使用する必要があり、一般的にはデジタルではなく羊皮紙とインクを使用しますが、デジタルでそれらを扱う人も確かにいます。 (20世紀のデータでも、第二次世界大戦時代のデータのアーカイブに使用されているケースを知っています)。
オクテット→文字(すでに.NETでうまく処理されている)、文字→コードポイント、コードポイント→書記素の順に進みたいことが多いため、書記素はさらに扱いにくいです。
今のところ、これを手に入れるためのフラグを立てます。
次のステップ:私たちが探しているのは、上記からのフィードバックを含む正式な提案です(タイプの実際の命名、およびInt32を使用するのではなくこれを使用する利点)。
提案されたAPIと初期実装の両方で問題を更新しました:
https://github.com/migueldeicaza/NStack/blob/master/NStack/unicode/Rune.cs
タイプの命名に関しては、タイプに対する有効な操作を探すことができる場所を用意することと、タイプ固有の機能を用意することの両方の問題です(いくつかの例については実装を参照してください)。
@migueldeicazaは、レビューの準備ができていることを示す前に、タイプの実際の命名に関する懸念についてどう思いますか?タイプが何であるかを説明するという点で、おそらくCodePointの方が優れていると思いますか?
コードポイントを名前として使用することについての議論は弱いと思います。
これを使用するのはひどい考えです。長期的には、適切なUnicodeサポートを取得したい場合は、既存のコードでの「char」の使用をすべて置き換える必要があります。
Rustのように「char」を使用できればよかったのですが、残念ながら、すでにそれを使用していて、壊れています。
この名前を受け入れて行くのは良い前例です。
code point
がここで使用する正しい用語ではないことに同意します。 少なくとも、Unicode標準に基づくと、10FFFF(http://unicode.org/glossary/#code_point)を超える値は含まれていません。
rune
という用語は好きではありません。 Unicodeやその他の場所で既存の用途があり、全体的に混乱を招くだけだと思います。 また、既存のユーザータイプと競合する可能性がかなり高いと思います(特に、「ルーン」が特定のゲームオブジェクトを表す可能性があるUnityなどの場合)。
ただし、C ++ 11のchar32_t
型をカバーする型のアイデアは、名前が違うだけで気に入っています。
Char32
には言いたいことがあります。 要するに、整数型の型名に似ています。 コードポイントレベルではなく、キャラクターの概念レベルで話します。 スクリプトの名前ではありません。
nint
を検討しているので、 nchar
どうですか?
先例はデータベースnchar
とnvarchar
にあります
ここで、 nchar
は国別文字/国別文字であり、 nvarchar
は国別文字変動/国別文字変動です。 ユニコードを保存できるフィールドタイプはどれですか。また、ISO標準もあります。どちらかわからないのですが、SQLかもしれません。
このUnicodeでのルーンの使用は何ですか? それは私にとってのニュースです。
U+16A0からU+16F8
Unicode標準の特定のコードページを参照するために使用されます。 このスレッドで数回取り上げられています:http: //unicode.org/charts/PDF/U16A0.pdf
ルーンではなく、ルーンです。
バッキング名(System.RuneまたはSystem.Char32)は、C#に投影されるラベルほど重要ではありません。
まず、はい、はい、そしてこれをもっとお願いします。 私はこのアイデアが大好きです(正直なところ、私は長い間同じようなアイデアを持っていました)。 実際、私たちはしばらくの間、Visual StudioのGit互換性でカスタム文字列クラスと文字構造体を使用してきました(GitはUtf-8で話し、すべてのトランスコーディングは非常に遅いです)。
静的メソッド名のトピックについて、任意の短い名前を避けることができますか? Char.IsPunctuation
が現在の方法であるとすると、それをRune.IsPunctuation
などでミラーリングできますか?
これが受け入れられると仮定すると(常に危険です)、固有のrune
またはc32
を使用できますか、それともchar
をSystem.Rune
実装に完全に置き換えることができますか?
unichar
またはuchar
をお勧めしますが、 uchar
は符号なし文字のように見えます。 ただし、どちらを選択しても、言語固有のエイリアスを取得できることを願っています。 私は個人的に、プリミティブ型に言語エイリアスを使用するのが大好きです。
また、 @whoisjにも同意します-短い/省略形よりも完全なメソッド名を間違いなく好むでしょう。
また、 @whoisjにも同意します-短い/省略形よりも完全なメソッド名を間違いなく好むでしょう。
IMO言語(およびそのライブラリ)は、完全な省略形の名前を選択するか、省略形(strcmpを含むC、memcpyなど)を完全に把握する必要があります。
または、
char
をSystem.Rune
の実装に完全に置き換えますか?
それはかなり明白な理由で重大な変化になるでしょう。
それはかなり明白な理由で重大な変化になるでしょう。
私のコメントは主に舌と頬で、希望に満ちていました。 文字の16ビットタイプは最初から間違いでした。
ネーミングの良いキャッチは、修正されます。
提供されているAPIには他にも小さな矛盾がありますが、それらの修正についても見ていきます。
@migueldeicaza
ルーンではなく、ルーンです。
ルーン文字は形容詞で、ルーン文字は名詞です。 すべてのルーン文字はルーンです。
_Runic_は形容詞、_rune_は名詞です。 すべてのルーン文字はルーンです。
「Cortana:define_'rune'_」は次のように思われます。
ローマ字に関連する古代ゲルマン文字の文字。
ああ、そうです、「ルーン」という言葉を見るとすぐに、「ルーンユニコードブロック」について語っている、誰も読んでいない仕様に関するこのあいまいな章を思い浮かべます。
😆トールキンを読んだ子供の頃の思い出を思い出します。
ᛁ᛫ᚦᛁᛜᚲ᛫ᛟᚠ᛫ᚱᚢᚾᛖᛋ
ええ、私は特にスペックについては考えていませんが、スペックが参照しているキャラクターのタイプについては考えています。
あなたはrune
と言います、そして私は魔法、ファンタジー、不可解なパズル、古代言語などについて考えます。
「ルーン」という単語が表示されず、すぐに「ああ、これは明らかに、値が16A0..16F8の範囲の一意の値に制限されるUnicode7.0ルーンブロックを指している」と思うのはうれしいです。
タナーはここでは単一の声であることを私は知っています、そしてあなた方の何人かはまだ「しかしミゲル、私は「ルーン」という言葉を見て、88の可能な値しか保持できないデータ型をすぐに思います」と考えています。 これがあなたが苦労している問題であるなら、私の兄/妹、私はあなたにニュースがあります:あなたは揚げるより大きな魚を持っています。
私はこのスレッドをしばらくの間、興奮と躊躇を混ぜ合わせて1か月余り続けてきました。 私は先月の国際化とUnicode会議に出席しましたが、.NETを扱ったプレゼンテーションはありませんでした。 .NETFrameworkには認識上の問題があります。 グローバリゼーション機能の歴史を考えると、必ずしも獲得できないものではありません。 そうは言っても、私はC#でのプログラミングが大好きで、真のグローバルコミュニティでの.NETの位置付けを強化する新機能を絶対に見たいと思っています。 この提案は、国際化コミュニティがソフトウェアに期待する標準を採用するという方向への良い一歩だと思います。
私の躊躇は、ほとんどの場合、型名についての口論でした。 Goの設計者が「ルーン」という名前を選んだのは事実ですが、それは上記の理由で問題があります。適切にルーンと呼ばれるコードポイントがあります。 尊敬される基準に近づき、仕様の一部である用語を再定義しようとする提案に同意するのは難しいです。 さらに、このタイプを正しく使用することに最も関心のある開発者はUnicode仕様を理解し、「ルーン」が実際に何であるかをよく理解している可能性が高いことを考えると、ほとんどの開発者がこの用語を知らないという議論は疑わしいものです。 用語を混ぜ合わせた場合に存在する可能性のある奇妙なことを想像してみてください。
Rune.IsRune(new Rune('ᛁ')); // evaluates to true
Rune.IsRune(new Rune('I')); // evaluates to false
もちろん、私はここで簡単な道を歩み、新しい名前を付けずに批評しました。 CodePoint
の以前の提案は、最も自己記述的なオプションだと思います(そして、それは元の問題の説明に表示されます)が、 char32
は、既存のプリミティブ型とより同等になります(ただし、すべてのコードポイントが文字であるとは限らないと言うことを躊躇します)。 目標がより良いUnicodeサポートを.NETに組み込むことである場合、私はそのパスを完全にサポートしますが、それを行うための最良の方法は仕様に従うことです。
3つの提案:
対応する書記素クラスも欲しいです。 このコンテキストでの書記素は、実際には1つ以上のルーン(コードポイント)のリストであり、最初のルーンは結合せず、残りのルーンは結合しています。 ユースケースは、開発者が「目に見える文字」のチャンクを処理する必要がある場合に使用します。 たとえば、+ GRAVEは、1つの書記素を形成する2つのルーンです。
ネットワーキングでは、バイトの塊を取得することがよくあります。これは、バイトが完全ではない可能性があるオブジェクトのような「文字列」に変換する必要があります(たとえば、いくつかのバイトについて通知されますが、マルチバイトシーケンスの最後のバイトはそうではありません。まだ到着していません)。 バイトのストリームをルーンのストリームに変換する明確な方法がわかりません。マルチバイトシーケンスの最後のバイトが欠落していると、次のバイトのセットを取得したときに修正される通常の状況と見なされます。
そして最後に、Unicode名を使用して、これをCodePointと呼んでください。 はい、ユニコードコンソーシアムは違いを説明するのにひどい仕事をしています。 しかし、解決策は、明確で使用可能なドキュメントを追加することです。 明確にするのを助ける代わりに、他の何かが問題を混乱させます。
私は結合要求をどこから始めればよいのか、Go、Rust、Swiftのいずれも、ルーン、Character、Unicode Scalar( System.Rune
の名前)でそのようなAPIを表示しません。 提案された実装を提供してください。
書記素クラスターでは、 System.Rune
とは別に追跡することをお勧めします。 SwiftはこれにCharacter
を使用しますが、Swiftは文字列を処理するための優れたモデルではありません。
バイトのストリームを適切なルーンに変換することは、より高いレベルのAPIに属する問題です。 そうは言っても、 System.Rune
実装と同じサブストレートを使用するustring
$実装を見て、これらのバッファーがutf8文字列にどのようにマップされているかを確認できます。
https://github.com/migueldeicaza/NStack/blob/master/NStack/strings/ustring.cs
APIにSystem.Rune
を導入して以来、まだ更新していないドキュメントですが、以下をカバーしています。
https://migueldeicaza.github.io/NStack/api/NStack/NStack.ustring.html
ネーミングに関しては、明らかにRustがchar
で最高のものですが、私たちはそれを台無しにしました。 次善の策はrune
で行くことです。 4文字を超えるものは、人々が正しいことをするのを邪魔するだけです。
申し訳ありません; CodePoint
は非常に良い名前だと思います。 それは自明で、記憶に残り、 cpでオートコンプリートします。
IsCombining
は間違いなく必要ですが、結合クラスも知っているので、 IsCombining
は、 IsCombining => CombiningClass != 0
またはIsCombining => CombiningClass != CombiningClass.None
であるため、大部分が砂糖です。 書記素クラスターは確かにその外側にありますが、出発点は、デフォルトのクラスタリング、並べ替えなどの結合クラスを知ることです。
CodePoint
は、コードポイントに関するタイプの優れた名前であり、4文字は、他の頻繁に使用されるタイプを処理する必要がある制限ではありません。 string
は50%大きく、定期的に使用することを妨げません。 ランダムに選んだ4文字は、Goの間違いを繰り返すよりも良い名前です。
uint
はCLSに準拠していないため、アストラル界をカバーするCLS準拠のコンストラクターはありません。 int
も必要です。
双方向の暗黙的な変換は、オーバーロードで悪いことが起こる可能性があるため、おそらく1つの方向を明示する必要があります。 どちらかは明確ではありません。 一方では、 uint
/ int
は、0未満または10FFFF 16を超える値は意味がないため、コードポイントよりも幅が広く、その変換を暗黙的に行うことで、より多くの既存のAPIをより迅速に使用できます。数字。 一方、数値からコードポイントにキャストしたいということは、その逆よりも頻繁に見られます。
uintはCLSに準拠していないため、アストラル界をカバーするCLSに準拠したコンストラクターはありません。 intも必要です。
それは、新しい固有の型が共通言語に導入されない限りです。
JonHanna-これらの3つのコンストラクターを意味しますか?
public staticimplicit operator uint(Rune rune);
public staticimplicit演算子Rune(char ch);
パブリック静的暗黙演算子ルーン(uint値);
「uint」ではなく「int」にする必要があります。 AFAICT、intは、アストラル(非BMP)平面のセット全体を簡単にカバーします。
@PeterSmithRedmondつまり、2つのコンストラクター(1つはchar
を取り、もう1つはuint
を取る)と同様に、1つはint
を取る必要がありますが、はい、 int
も必要です。 implicit
とは何か、 explicit
は別の質問です)。 $#$ 6 $#$を使用できる言語でも、 uint
を使用しても問題はありません。 結局のところ、それは非常に自然な一致です。
これがSystem.Charに置き換わる場合は、「算術」を実行できる必要があります(つまり、==、!=、>、<+、-、*、/が不明)。さらに重要なのは、このリテラルのサポートである必要があります。たとえば、次のように入力できます。
rune r = '𐍈'; // Ostrogothic character chose on purpose as in UTF16 will be a "surrogate pairs"
文字は、ルーン文字よりもユニコード(および一般的にはネット)でさらに正確な意味を持ちます。
これをUnicode文字タイプにする場合は、Unicodeの命名規則に従う必要があると思います。 これは_"コードポイント"_を意味します。
コードポイント。 (1)Unicodeコードスペースの任意の値。 つまり、0〜10FFFF16の整数の範囲です。 (セクション3.4「文字とエンコード」の定義D10を参照してください。)すべてのコードポイントがエンコードされた文字に割り当てられるわけではありません。 コードポイントタイプを参照してください。 (2)コード化された文字セット内の文字の値または位置。
あるいは、あきらめてアヒルを「アヒル」と呼び、Unicode文字(別名uchar
)と呼ぶこともできます。
代わりにSystem.CodePoint
を使用するようにこれを解決してみませんか?
私見では、Unicodeの用語の観点からはより適切であり、Javaの世界の他の人々がそれを使用しています。 したがって、独自の用語を使用する代わりに、Unicodeの用語を順守しましょう。 .NETのStringはcharのコレクションであり、このcharのコレクションはUnicodeベースであるという事実も知っているので、.NETでの一般文字と文字列の実装に関しては、より理にかなっており、より普遍的です。
私はJavaと.NETの両方の世界に住んでいたので知っています。
そして多分これに関するドラフト実装を始めましょう。
実際には、これには2つのコンポーネントがあり、両方が必要になります(@GrabYourPitchforksによるhttps://github.com/dotnet/corefxlab/issues/1799のCodeUnit)
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
は、可変幅エンコーディングを表すため、およびSpan<ubyte>
で使用して、テキストAPIがテキストタイプで使用可能であり、生のバイトでは使用できないようにするために重要です。
CodePoint
/ uchar
は、賢明な処理にとって重要です。 たとえば.IndexOf(❤)
は、 ubyte
自体を使用して、マルチバイトのUnicode文字を検索することはできません。 ubyte
を超える列挙は危険にさらされるため、列挙子はuchar
単位で動作する必要があります。
2つの提案を組み合わせると、次のようになります。
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
}
}
プロトタイプの実装でUnicodeScalar
を使用して、Unicodeスカラー値(U + 0000..U + 10FFFFの範囲の値、代理コードポイントを除く)とUtf8Char
を参照しています。 UTF-8コードユニットを参照します。 多くの人が_UnicodeScalar_ではなく_Rune_を好むようです。 あまり気にしませんが、「Unicodeスカラー値」という用語はUnicode仕様で使用されている用語と同じです。 ;)
.NET Frameworkには、「テキスト要素」の概念もあります。これは、1つ以上のスカラーであり、組み合わせると単一の分割できない書記素を作成します。 詳細については、MSDNをご覧ください。 特に、文字列を列挙する場合は、コード単位( Utf8Char
またはChar
)、スカラー値( UnicodeScalar
)、またはテキスト要素で列挙する必要があります。特定のシナリオ。 理想的には、StringとUtf8Stringの両方で3つのタイプすべてをサポートします。
プロトタイプのAPIサーフェスは完成しておらず、急速に変更される可能性がありますが、 https://github.com/dotnet/corefxlab/tree/utf8string/src/System.Text.Utf8/Systemで現在の考え方を確認できます。 https://github.com/dotnet/corefxlab/blob/master/src/System.Text.Primitives/System/Text/Encoders/Utf8Utility.cs。
少しオフトピック:
「テキスト要素」は、UAX dotnet / corefx#29の「GraphemeClusterBoundaries」で定義されたセグメンテーションである必要がありますか?
using System;
using System.Globalization;
class Program
{
static void Main()
{
var e = StringInfo.GetTextElementEnumerator("👩🏻👦🏼👨🏽👦🏾👦🏿👩🏼👨🏽👦🏼👧🏽👩🏻👩🏿👧🏼👧🏾");
while (e.MoveNext())
{
Console.WriteLine(e.GetTextElement());
}
}
}
期待される結果:
👩🏻👦🏼
👨🏽👦🏾👦🏿
👩🏼👨🏽👦🏼👧🏽
👩🏻👩🏿👧🏼👧🏾
実結果:
👩
🏻
👦
🏼
👨
🏽
👦
🏾
👦
🏿
👩
🏼
👨
🏽
👦
🏼
👧
🏽
👩
🏻
👩
🏿
👧
🏼
👧
🏾
UnicodeScalar
はまだ非常に簡単に入力できます。 u s cスペース(オートコンプリート)これは正しい、最も自己記述的な用語なので、私は本当にそれを取得したいと思っています。
@ufcppそれは良い点です。 そのための新しい問題を自由に開いてください。 互換性の理由で動作を変更できない場合は、そのタイプを廃止し、仕様に準拠した書記素列挙子を作成することをお勧めします。
ubyte
/ uchar
は紛らわしいです。 ushort
/ uint
/ ulong
で確立された規則を考えると、 unsigned char
/ unsigned byte
のように読み取られます。 おそらくchar8
/ u8char
とchar32
/ u32char
の方が明確ですか?
いずれにせよ、UTF-8コードユニットとコードポイントが次のとおりであるかどうかについて、私たちはずれていると思います。
byte
、 int
などDateTime
、 Guid
などそして、その決定を前提として、コードポイント関連のAPIをどのように公開しますか?
オプション1は、C ++ 17のようにchar8、char16、およびchar32プリミティブ(および付随するu8string、u16string、およびu32string)を介してテキストを処理することを意味します。 rune
としてのchar32は、すでにchar
としてchar16があり、 char8
にも3番目の名前が必要なため、不適切な名前です。
オプション2は、byteとint/uintがUTFコードユニットとコードポイントを格納するのに「十分」であることを意味します。 これは、すべての文字列がUTF-16のままであることを意味します。 CodePoint
/ rune
は、バイナリ表現ではなくCode Point
セマンティクスの問題を解決します。これは、IOを対象としたものではありません。
IMO UTF-8 / UTF-32は単なるデータ形式です(オプション2)。 それらをデータ(byte / int)として扱います。 CodePoint
は、私にとってint
よりもDateTime
またはGuid
(別の識別子*)に似ています-低レベルのプリミティブ型ではなく、IOで直接サポートされていません(つまり、BinaryWriter)、組み込み関数は必要ありません。
@miyu corefxlabで紹介しているプロトタイプは、オプション1に近いものです。コードユニットを表す特定のデータ型があり、これらのデータ型はテキストデータの内部表現用であり、ネットワークを介してテキストデータを送信するために使用することはできません。 (ご指摘のとおり、.NETは今日すでに次のように機能します。 System.Char
はUTF-16文字列のコード単位ですが、 System.Char
をネットワーク経由で送信することはできません。)
さらに、 byte[]
/ Span<byte>
など(これはすべてのデータのバイナリ表現であり、I / Oに適しています)とUtf8String
のようなプリミティブ型の間で変換するAPIがあります。 String
/ Guid
/など。これらのいくつかは他のものよりも単純です。 たとえば、i / oで使用するためにReadOnlySpan<byte>
を返す便利なUtf8String.Bytes
プロパティを公開できます。このプロパティゲッターは、O(1)の複雑さを持つことができます。 String.ToUtf8Bytes()
の便利なメソッドがあることは想像できますが、 String
タイプではそのようなプロパティを導入しません。 また、 Utf8String.Bytes
プロパティが存在する場合でも、 Utf8String
インスタンスを直接列挙する要素タイプはbyte
ではありません。 Utf8CodeUnit
(名前は未定)またはUnicodeScalar
のどちらか、開発者が構築したいアプリケーションの種類に適していると思われる方になります。
愚かな考え- wchar
(_wide char_)はどうですか? 現在、ほとんどのCおよびC ++コンパイラ環境(Windows以外)は、32ビットコードユニットと同等の機能を表すためにすでにwchar_t
を使用しています。 Windowsは注目すべき例外であり、 wchar_t
は16ビット型として定義されていますが、今日Windowsでp / invokeする開発者は、.NET char
間のビット幅の違いをすでに認識している必要があります。 char
。
タイプ/キーワードwchar
は命名規則に違反しますが、検討のためにこれを捨てるだけです。
愚かな考え-
wchar
(ワイド文字)はどうですか?
私のために働く
タイプ/キーワード
wchar
は、命名規則に違反します...
短いC#言語のキーワードを取得するようには聞こえません
https://github.com/dotnet/apireviews/pull/64#discussion_r196962756これらのタイプの言語キーワードを導入する可能性は非常に低いようです。これらはコンテキストに依存する必要があるためです(つまり、次のタイプに解決できるかどうかによって異なります)。キーワードで表されるタイプではなく、そのタイプにバインドする必要があるキーワードの名前)。
だから私たちが何かいいものが欲しいなら...すなわちNotLotsOfCapitalFullWords
..。
私は通常、.NETの命名規則が好きですが、長い名前は基本的にint
にとって少し不快です。これは、ジェネリックスやループ変数としても使用される可能性があります。
たとえば、誰もしません
foreach (Int32 i in list)
{
// ...
}
彼らはいますか? (もちろん...)
foreach (UnicodeScalar us in str)
{
// ...
}
はるかに悪い
foreach (wchar c in str)
{
// ...
}
大丈夫そうです...
rune
、 wchar
、およびuchar
(他のスレッドで提案)はすべて私には良い音です。 string
のピアへの提案はありますか? wstring
、 ustring
、またはその他?
...そしてC#言語のキーワードを取得してみませんか? 確かに、最初のリリースで1つを持たないことは理にかなっていますが、これが将来的に文字列処理に進む場合、キーワードを持たないことは不誠実であるだけでなく、その採用に対して明らかに敵対的です。
/ CC @MadsTorgersen @jaredpar
C#言語のキーワードを取得してみませんか?
新しいキーワードは、100%の確率で変化をもたらしています。 あなたがどんな言葉を選んだとしても、彼らのプロジェクトの至る所で使われているその名前のタイプを持っている会社がそこにあります。 唯一のオプションはコンテキストキーワードです。たとえば、 var
です。
私はこれに文脈上のキーワードを使用することについて複雑な気持ちを持っています。 既存のタイプキーワード( int
、 string
など)には、実際のタイプ名( Int32
、 String
)よりも具体的な利点があります。
string
:これは、コンパイラがcorelibとして識別するアセンブリ内のタイプSystem.String
を指します。 この名前には、あいまいさはありません。String
:コンパイラはこのタイプをまったく理解していません。 これは他のタイプと同じであり、定義したタイプと同じルックアップルールをすべて通過します。 string
と同等である場合と、そうでない場合があります。ここでコンテキストキーワードを紹介すると、 rune
は次のいずれかになります。
System.Rune
Go
について読んだときに定義したタイプrune
#$。rune
String
同じくらいあいまいであるため、コンテキストキーワードとして使用することに確固たる利点はありません。
ところで:これが、 String
string
を使用する必要がある理由です😄
ところで:これが、
String
string
を使用する必要がある理由です
人々が言語キーワードを望んでいると思う理由の99%。 他の1%は「見栄えが良い」だけです😏
「ルーン」キーワードが非常に嫌いな場合は、親指を下に向けてください。
より良い単語はグリフです。これは、タイポグラフィの要素記号の一般的な概念をすでに表しているためです。
ルーンは、Unicodeによって皮肉なことに定義されている特定のタイプのグリフです。 先行技術として囲碁を参照することはややばかげています。 ルーンの先行技術は、西暦150年に書き戻されたものと実際の物理的なルーンストーンです。 レドモンドの誰かがルーンと思っているものではありません。 .NETには通常適切に設計されたAPIサーフェスがあるため、このような既存の概念を再定義しようとするのは珍しいことです。 これは非常に貧弱なAPIネーミングのまれな例外であり、不満を表明したいと思います。
より良い単語はグリフです。これは、タイポグラフィの要素記号の一般的な概念をすでに表しているためです。
問題は、「グリフ」は、Unicodeを表示可能なテキストにレンダリングするときに使用される用語です(from: utf8everywhere.org )
グリフ
フォント内の特定の形状。 フォントは、タイプデザイナーによって設計されたグリフのコレクションです。 一連のコードポイントを指定されたフォント内の一連のグリフに変換するのは、テキストシェーピングおよびレンダリングエンジンの責任です。 この変換のルールは複雑で、ロケールに依存する可能性があり、Unicode標準の範囲を超えています。
先行技術として囲碁を参照することはややばかげています。
Utf-8の作成時に使用されたRobPikeおよびKenThompsonという用語の使用https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt
Rob Pikeは現在Goに取り組んでいるため、元の用語を使用しています。
ルーンは、Unicodeによって皮肉なことに定義されている特定のタイプのグリフです。
ルーンはUnicodeで定義されていますが、ルーンは定義されていません
ルーンはUnicodeで定義されていますが、ルーンは定義されていません
これは正確な記述ではないと思います。最新のユニコード仕様(http://www.unicode.org/versions/Unicode11.0.0/UnicodeStandard-11.0.pdf)では、「ルーン」のヒット数が37です(有効なのは36のみです)。 、最後はより大きな単語の一部です)、ルーン文字の個々の文字を参照するために常に使用されます。
これは正確な記述ではないと思います。最新のUnicode仕様では、「ルーン」が37ヒットしています。
動機を説明する本文。 文字名またはテキストブロック名(ルーン文字とルーン文字の場合)には含まれていません
動機を説明する本文。 文字名またはテキストブロック名(ルーン文字とルーン文字の場合)には含まれていません
わかりました、公平です。 しかし、現在のUnicode仕様では「ルーン」という用語が定義されておらず、使用される場合は「ルーン文字」を説明する有益なテキストであるという問題に戻ります。
物事を正式に定義して説明するために使用するのは、「コードポイント」と「コードユニット」です。
短くする必要があります。さもないと使用法が醜くなります
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);
}
長さについては、私は完全にCodePoint.IsWhiteSpace
とstr.GetCodePointAt
に行きますが、 Rune
も楽しいので、気にしません。
@ jnm2文字列に関しては、 GetCodePointAt
は使用しません。 あいまいすぎます。たまたまそのインデックスにあったchar
が必要かどうかはわかりません(すべてのchar
(ペアになっていないサロゲートも含む)も有効なコードポイントであるため)またはスカラー/たまたまそのインデックスにあったルーン。
@GrabYourPitchforks GetRuneAt
は同じ問題を回避できますか、それともどちらも意味がないと言っていますか?
@ jnm2このシナリオでは、特にCodePoint
はあいまいすぎると言っていました。 それ以外の場合、メソッド名GetXyzAt
は、最終的に入力されるタイプ名Xyz
と一致する必要があります。
参考までに、コア実装がチェックインされました(https://github.com/dotnet/coreclr/pull/20935を参照)。 corefxに伝播するまでしばらくお待ちください。そうすると、refAPIがhttps://github.com/dotnet/corefx/pull/33395経由で提供されます。 この問題を開いたままにするか、適切と思われる場合は解決してください。
記録のためだけに、誰かに影響を与えたり、何かを変更したりできるとは思っていません。
より良い単語はグリフです。これは、タイポグラフィの要素記号の一般的な概念をすでに表しているためです。
問題は、「グリフ」は、Unicodeを表示可能なテキストにレンダリングするときに使用される用語です(from: utf8everywhere.org )
「ルーン」は、Unicode、トランジスタ、Microsoft、またはオープンソースが存在するずっと前から、1000年以上にわたって使用されてきたため、この一連の推論はルーンもサポートしていません。 少なくともそれは、明らかに一貫性のない異なる提案に異なる基準を恣意的に適用するものがあることを示しているので、おそらく最も首尾一貫した議論ではなく、誰が最初であるか、最も騒々しいのかについてです、私は何を知っていますか? 私はプロセスを理解しようとしている後発者ですが、それは意味がありません。
先行技術として囲碁を参照することはややばかげています。
Utf-8の作成時に使用されたRobPikeおよびKenThompsonという用語の使用https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt
Rob Pikeは現在Goに取り組んでいるため、元の用語を使用しています。
GoとRobPikeは、このトピックについて比較的新参者です。 実際、彼らの意見は、ルーンが歴史的に、そして人気のある文学や社会で何であるかを定義するという点では、いくぶん無関係です。 ロブは自分でルーンストーンを手で叩いたわけではないので、ルーンが何であるかを定義する資格はほとんどありません。 彼は自分でルーン文字を書いたり読んだりすることさえできないに違いないが、それは私の推測である。 せいぜい彼はエンコーディングを通じてその概念を捉えることができますが、漢字、アラビア語の文字、ハングル、またはスマイリーフェイスがルーン文字であると言うことはできません。またはそのようなもの。 見た目、今ではすべてがルーン文字になる可能性があります。つまり、ルーン文字は、テキストのエンコードの領域で難解なものを指す4文字のワイルドカード用語にすぎません。
ルーンは、Unicodeによって皮肉なことに定義されている特定のタイプのグリフです。
ルーンはUnicodeで定義されていますが、ルーンは定義されていません
Unicodeは、ルーンまたはルーンが何であるかを再定義することは想定されていません。 彼らがそうするなら、彼らは彼らの任務を踏み越えています。 彼らは、ルーンが何であるかを大衆に伝えるビジネスを持っていません。 実際、彼らには新しい言語や文字システムを定義するビジネスはまったくありません。 彼らは、千年前からすでに明らかに過負荷になっている言葉を適切に使用し、新しい概念を発明したように歓声を上げて走り回ることはできません。 ルーン文字はルーンのみで構成されており、ルーンはすでに確立された概念です。 あなたが通りのランダムな人にルーンが何であるかを尋ねるならば、彼らはユニコードについて考えません。
上記のすべての問題に加えて、ルーンは最悪の部分である貧弱な比喩です。 それは何も明確にしません。 それは単に別のレベルの混乱を追加します。 ルーン文字は特定の文化で使用される歴史的な書記体系であるという文脈で誰もが参加するため、このトピックを初めて使用する人は、曖昧さ回避の説明と読書を繰り返す必要があります。 説明は次のようにする必要があります:「ルーンはUnicodeコードポイントです」。 「でも、それをコードポイントと呼んでみませんか?」 「まあ、長すぎるから。」または「誰かがルーンが好きだと決めた」。 つまり、基本的に、誰かが9文字は4文字と比較して多すぎると考えているため(Intellisenseでオートコンプリートされており、Java Kingdom Of Nounsとは何も比較されていない場合でも)、この混乱に対処し、これを数千人に説明する必要があります。 Unicodeに手を出す必要があるかもしれない開発者の。 コードで頻繁に使用する場合は、usingステートメントを使用して用語を短縮してください。
UnicodeCodePointである必要はなく、単にCodePointにすることもできます。 これはすでにユニークです。 「CodePoint」より長いAPI用語がたくさんあるので、それで十分です。 それでも長すぎる場合は、省略形を付けたusingステートメントを使用してください。
私は、これが実際にはあまり価値をもたらさない、または有用なものに論理的な根拠を持たない、それらの落とし穴のインタビューの質問の1つになると予想しています。 少なくとも比喩「マイルストーン」については、石と岩から派生した概念に基づくソフトウェア開発で使用される象徴的な単語のトピックに取り組んでいますが、マイルストーンには実際の説明的な意味があります。 誰もが知っているコンセプトをすぐに伝えます。 ああ、マイルストーンです。長い旅をしていて、トレイルを通り過ぎるときのように。 それは実際に何かを視覚化するのに役立ち、即座に管理言語になることができる素晴らしい現実世界の比喩です。 トピックに精通していない限り、このようにルーンについて話している人は想像できません。その時点で、それがコードポイントの単なるギミック用語であることをすでに知っているでしょう。
より良い単語はグリフです。これは、タイポグラフィの要素記号の一般的な概念をすでに表しているためです。
問題は、「グリフ」は、Unicodeを表示可能なテキストにレンダリングするときに使用される用語です(from:utf8everywhere.org)
「ルーン」は、Unicode、トランジスタ、Microsoft、またはオープンソースが存在するずっと前から、1000年以上にわたって使用されてきたため、この一連の推論はルーンもサポートしていません。
私のポイントは、「グリフ」という単語は、テキストのレンダリングの概念の1つとしてすでに使用されているため、問題があるということでした。 特定のフォントでのその文字のグラフィック表現。 したがって、文字は多くの異なるグリフで表すことができます。
...再び@benaadamsが10,000メートルの物事のビューと正解を持っています😁
正直なところ、私たちは古い格言と一緒に暮らす必要があります。「一部の人々を常に幸せにし、すべての人々をいつか幸せにすることはできますが、すべての人々を幸せにすることはできません。時間です。」 これは非常に前者の状況です。
紋章?
Exit, pursued by a bear.
このAPIを広範に使用する人として、私はコードポイントに強い投票をしています。 Unicodeの用語はすでに十分に混乱しており、矛盾はすでにたくさんあります。 どこでも「コードポイント」と言えば、私の人生はずっと楽になります。
私は今ベッドに横たわっています。 横向きにすると、壁に立てかけられたホワイトボードに直面します。 何ヶ月もの間、そのホワイトボードにはさまざまな落書きやグラフがあり、C#でIDNを効率的に処理する方法を見つけようとしています。 地獄の奥から召喚した遺物のように扱っています。 それが説明している論理を説明しようとすると、説明できません。
どうか、私の人生を難しくしないでください。 コードポイントはコードポイントです。 ルーン、グリフ、キャラクター、書記素、さらにはシンボルでもありません。 人間にとって意味のあるものを表す必要はありません。制御コードである可能性があります。 「ルーン」という名前が示すように、視覚的なシンボルを表していない場合があります。 これは単なるコードポイントです。
より具体的な議論は、「ルーン」は単一の書記素の表現を意味するということですが、これはほとんどの場合そうではありません。 コードポイントの数と書記素の数を数えると、2つの非常に異なる数が得られる可能性があります。 同じ一連の書記素は、2つの異なる一連のコードポイントで表すことができます。
より良い単語はグリフです。これは、タイポグラフィの要素記号の一般的な概念をすでに表しているためです。
それはさらに悪いことです。 単一のコードポイントは複数のグリフで表すことができ、単一のグリフは複数のコードポイントを表すことができます。 正確なマッピングは、システム、プログラム、書体によって異なります。
これらの言葉はすべて、非常に具体的な技術的意味を持っています。 この提案の文脈では違いは重要ではないように見えるかもしれませんが、他の場所、特に英語以外の言語では、実際の結果があります。
ドイツ語のように一般的な言語であっても、テキストの処理がいかに難しいかの一例として、次のようになります。
ß
を大文字に変換すると、 SS
が得られます。ss
になります。問題:
char.ToUpper('ß')
は何を返す必要がありますか? (1文字を返す必要があります。)これは、用語が問題を引き起こす状況の直接的な例ではありませんが、通常は考えられない種類のエッジケースがあることを示しています。 各用語に明確で一貫した意味を与えることは、プログラマーがこれらの問題を伝えるのに役立ちます。 チームメイトに書記素を数える関数を書いてもらうと、彼らは何を数えるのか、そしてそれをどのように行うのかを正確に知っています。 私が彼らにコードポイントを数えるように頼むと、繰り返しますが、彼らは何をすべきかを正確に知っています。 これらの定義は、使用している言語やテクノロジーとは無関係です。
JavaScript開発者にルーンを数えるように頼むと、彼らは私が3つの頭を持っているように私を見るでしょう。
ウィキペディアは言う
Unicodeは、0hexから10FFFFhexの範囲で1,114,112コードポイントのコードスペースを定義します
コードポイントは正式名称のようです。 私はこのスレッドを読みましたが、コードポイントが正しくない理由についての強制的な議論は見つかりませんでした。
コードポイントがここで使用する正しい用語ではないことに同意します。 少なくとも、Unicode標準に基づくと、10FFFF(http://unicode.org/glossary/#code_point)を超える値は含まれていません。
多分その文はちょうど間違っていますか? 「コードスペース内の任意の値」と表示されます。 つまり、それは明らかにすべてを意味し、同時に整数を間違えます。
また、 「ルーン」には、Unicodeとは関係のない現実世界の意味があります。 ドイツでは、ルーン文字にはナチスが言及するのが好きだった「ゲルマン」の歴史があるため、「ルーン」という言葉にはナチスの意味があります。
「ルーン」は紛らわしい名前だと思います。 ここの誰かが本当に「ルーン」が好きですか、それとも正確さに基づいたそれに対する議論です。 直感的には、それは本当に悪い名前です。
多分その文はちょうど間違っていますか? 「コードスペース内の任意の値」と表示されます。 つまり、それは明らかにすべてを意味し、同時に整数を間違えます。
その文は正しいです。 コードスペースはU+0000からU+10FFFFです。 Unicodeは理論的にはそれを超えて拡張される可能性がありますが、UTF-8とUTF-16を壊してしまいます。 新しいエンコーディングが必要です。
編集:実際には、UTF-16の破損については引用しないでください。ただし、UTF-8が破損することは間違いありません。 UTF-8は間違いなく0xFFFFFF(2 ^ 24 -1)を表すことはできません。
編集2:明確にするために、Unicodeは、コードポイントがU+10FFFFを超えることはできないと述べています。 これは、現在0x110000のコードポイントがあることを意味するわけではありません。これらのコードポイントのほとんどは割り当てられていません。
@Zenexer @GSPP
現在マスターにチェックインされているこのタイプ( System.Text.Rune
)は、非常に具体的に「Unicodeスカラー値」にマップされます(用語集を参照)。 値-1
、 0xD800
、または0x110000
から構築しようとすると、型のctorは例外をスローします。これは、これらがUnicode仕様によるスカラー値ではないためです。 メソッドへの入力としてRune
パラメーターを使用する場合、そのパラメーターに対して検証チェックを実行する必要はありません。 型システムは、有効なスカラー値から構築されていることをすでに確認しています。
Re:ケース変換、.NET Frameworkのすべてのケース変換APIは、特に明記されていない限り、単純なケースフォールディングと呼ばれる手法を使用します。 単純な大文字小文字の区別の規則では、入力スカラー値について、出力の小文字、大文字、およびタイトルケースの形式もそれぞれ正確に1つのスカラー値であることが保証されています。 (0〜9の数字や句読記号などの一部の入力には、大文字と小文字の変換マップにエントリがありません。これらの場合、_ToUpper_のような操作は、入力スカラー値を返すだけです。)さらに、単純な大文字小文字の区別では、入力がBasic Multilingual Plane(BMP)では、出力もBMPに含まれている必要があります。 また、入力が補助面にある場合、出力も補助面にある必要があります。
これにはいくつかの結果があります。 まず、 Rune.ToUpper
とその友人は、常に単一の_Rune_(スカラー)値を返します。 次に、 String.ToUpper
とその仲間は、入力とまったく同じ長さの文字列を常に返します。 つまり、大文字と小文字の変換操作の後、'ß'(最小のエスツェット)を含む文字列は、使用されているカルチャに応じて、'ß'(変更なし)または'ẞ'(大文字のエスツェット)を含むことになります。 ただし、文字列の長さが変更されるため、「SS」は含まれません。また、公開されているほとんどすべての.NETケース変換APIは、単純なケースフォールディングルールを使用します。 第3に、 Utf8String.ToUpper
とその友人(まだチェックインされていない)は、_Length_プロパティが入力値の_Length_プロパティと一致する値を返すことが_保証されていません_。 (文字列内のUTF-16コード単位の数は、単純な大文字小文字の区別の後で変更できませんが、文字列内のUTF-8コード単位の数は変更できます。これは、BMP値がUTF-16およびUTF-によってエンコードされる方法によるものです。 8.)
単純なケースフォールディングルールではなく、複雑なケースフォールディングルールを内部的に使用する.NETAPIがいくつかあります。 String.Equals
、 String.IndexOf
、 String.Contains
、および同様の操作では、文化に応じて、複雑なケースフォールディングルールが使用されます。 したがって、カルチャが_de-DE_に設定されている場合、_CurrentCultureIgnoreCase_を渡すと、1文字の文字列「ß」と2文字の文字列「SS」は同じように比較されます。
@GrabYourPitchforks私は主に名前の選択に反対しています。 大文字と小文字を区別する例は、Unicode(および一般的なテキスト)がいかに複雑であるかを強調するためのものです。 正規化を処理する方法がある限り、ユースケースではとにかくすべてをNFKDに変換するので、単純な操作がどのように機能するかはあまり気にしません。
その文は正しいです。 コードスペースはU+0000からU+10FFFFです。 Unicodeは理論的にはそれを超えて拡張される可能性がありますが、UTF-8とUTF-16を壊してしまいます。 新しいエンコーディングが必要です。
ちょっと気を付けてください(または、人々が興味を持っている場合):理論的には、UTF-8アルゴリズムは最大42ビット(プレフィックスバイト0xFFおよび6ビットペイロードの7バイト)で機能し、最初の仕様は31全体をカバーしていましたこれらの古いバージョンのUniversalCharacterSet(UCS4)の
UTF-16の場合、状況はより困難です。 ただし、32ビット以上の「エスケープ」として上部平面のコードポイントを予約することはできます。 プレーン3から13は現在定義されていないため、「低サロゲートプレーン」と「高サロゲートプレーン」の2つを予約できます。 次に、32ビットコードポイントを2つの16ビット値(各プレーンに1つ)に分割し、各値を2つの「クラシック」サロゲートを使用してエンコードします。実質的にはそれぞれ16ビットの4つのコードユニットを使用して32ビットコードポイントをエンコードします。
ところで、AFAICSのユニコードコンソーシアムは、U + 10FFFFを超えるコードポイントを割り当てることは決してないと公に述べているので、実際には、それが実際に発生する前に、私は長い間引退することを望んでいます。 :ウィンク:
現在マスターにチェックインされているこのタイプ(
System.Text.Rune
)は、非常に具体的に「Unicodeスカラー値」にマップされます。
@GrabYourPitchforksその説明に感謝します。 これは、構造体がコードポイントを表していないことを意味します。 そのため、その名前は確かに正しくありません。
UnicodeScalar
は名前としては難しすぎると思います...
@GrabYourPitchforks 、この問題のために何をする必要がありますか?
@stephentoub 3.0のインボックスRune
タイプに追加の機能は計画されていませんが、 @ migueldeicazaは、書記素クラスターなど、タイプの範囲を拡張するためのアイデアを持っていました。 (私たちが同梱している最も近いものはTextElementEnumerator
で、これは非常に時代遅れのタイプです。)これらのアイデアのいくつかはこのスレッドで乱用されましたが、具体的なものはまだありません。
コミュニティがシナリオについてさらに話し合いたい場合に備えて、この問題を開いたままにしておくことも、具体的な提案をしたい場合は、新しい問題を開くように指示することもできます。 TBH私は強い好みはありません。
ありがとう。 ルーンはすでに導入されており、ここで概説されているAPI(またはその近似)はすでに公開されているので、これを閉じましょう。 追加のサポートは、別の問題で対処できます。
それで、これはこの時点で本質的に安定していますか? 正直なところ、この恐ろしい名前は、Unicodeについて適切で正確な情報源から得られる情報と一致せず、印刷されない文字ではなくグリフを暗示するという不幸なニュアンスを持っているためです。あなたの平均的なプログラマーによるUnicodeのすでに恐ろしい理解を悪化させます。
これがこの時点で統合されていることは知っていますが、 Rune
の部分にチャイムを入れたいだけで、名前について意見の相違がある人もいます。
私はプラン9で最初にRune
に遭遇しましたが、他の人と同じようにGoなどで見ました。 msdocsがRune
をリストし始めたとき、私はそれが何であるかを読む前に正確に知っていました。
Plan 9とGoの少なくとも2つのインスタンスでは、 Rune
という名前を使用してUTF-8を担当する個人がいます。 彼らはすでにこれらの懸念について考えていて、それでもRune
は妥当だと思っていたと言っても過言ではありません。 Runicは、一部の伝統主義者を除いて、もはや実際には使用されている書記体系ではありません。 また、 Rune
は、基本的にここでの書記素を意味するのと同じように、そのシステムの書記素を意味します(制御文字などの場合を除く)。
ネーミングに少し間違いがあります。 ルーン文字は非常に古い書記体系であり、平均的なプログラマーがそれを混乱させることはないでしょう。適切なUnicode「文字」のデファクトスタンダードはすでにRune
十年前のものです。
@Entomy
本質的にここでの書記素を意味するのと同じように(制御文字のような場合を除く)。
これは単に真実ではありません。 Unicodeには、複数の書記素(通常は文字と発音区別符号の組み合わせ)を表す合成済みコードポイントが多数含まれており、これらはフランス語やスペイン語などの言語の記述に一般的に使用され、これらの言語のコンピューター化されたテキストのほとんどすべてがこれらのコードを使用しますポイント。
逆に、単一のコードポイントが1つの書記素を表す場合でも、それらが_grapheme cluster_に結合されることは非常に一般的です。これは、ほとんどのインドの言語でテキストを適切に処理するために不可欠です。 したがって、矢印キーを使用して移動するときにユーザーが認識する1つの文字は、多くの場合、順番に複数のコードポイントに対応します。 したがって、コードポイントと書記素または書記素クラスターのいずれかとの間で簡単に対応することはできません。 プログラマーがこの時点でキャラクターを奇妙で奇抜なものと見なすことに慣れていることを考えると、「キャラクター」でさえおそらくより良い名前になるでしょう。一方、「ルーン」は、ユーザーが知覚するキャラクターの境界を理解する問題がプログラマーにとって解決されたという印象を与えます。すでに実際にはそうではありませんでした。
msdocsがルーンをリストし始めたとき、私はそれが何であるかを読む前に正確に知っていました。
ルーンという名前が書記素をうまく説明しているとあなたが思ったという事実は、私がここで抱えている問題の非常に良い証拠です。「ルーン」という名前は、そのような対応があると推測しやすくすることで、プログラマーに誤った安心感を与えます。
Plan 9とGoの少なくとも2つのインスタンスでは、
Rune
という名前を使用してUTF-8を担当する個人がいます。
ケン・トンプソンとロブ・パイクに敬意を表しますが、ここでの彼らの仕事は、基本的に、一連の可変長整数をエンコードするための非常に巧妙なスキームを考案することでした。 彼らは全体としてUnicodeの専門家ではなく、私はこの問題について彼らに非常に強く反対しています。 私もUnicodeの専門家ではないことは認めますが、ここでの権威への訴えは思ったほど強くはないと思います。
そして、適切なUnicode「文字」のためのルーンの数十年前の事実上の標準がすでにありました。
あなたが言う「標準」? ほとんどの場合、この2つが名前を押し上げており、Nimなどのいくつかのマイナーなプログラミング言語がGoからそれを採用しています。 そしてもちろん、コードポイントは、選択、矢印キーの移動、書記素、または書記素クラスターのいずれの意味でも、単一の「適切なUnicode文字」を表していないことをもう一度繰り返す必要があります。
...本質的にここでの書記素を意味します...
はい、正確ではありませんが、大まかに十分に近いためです。 書記素は、少なくとも言語学で定義されているように、書記体系を構成し、音素を表現するために使用される正書法のコンポーネントです。 これらは1:1のものではありません。 音節文字とロゴ音節文字では、単一の書記素が複数の音素、通常は子音と母音のペアを表すことができます。 逆に、アルファベット順の言語では、特定の単語に応じて、古語法のethとthornの原因となる英語の「th」など、単一の音素を表す複数の書記素の場合がよくあります。 そうすると、「á」のような文字がそれ自体の固有の文字なのか、それともアクセント付きの「a」なのかについて、言語間で合意を見つけることさえできません。 何千年も前の言語で一貫性を確立することすらできません。 その上に完全に一貫した追加、つまりこれらのエンコーディングはありません。
あなたは非常に厳密なセマンティクスを主張しているので、UNICODEが「書記素クラスター」と呼ぶものは、言語学では単一の書記素にすぎないことがよくあります。 これは無効なUNICODEですか? いいえ。これは、UNICODEの名前を変更する必要があることを意味しますか? いいえ、なぜですか? コンテキストのため。 フィールドには独自の用語があり、単一のフィールド内に矛盾がない限り、それは問題ではありません。
名前が大したことではないと思います。 Msdocsは、要約にRune
が含まれていることを明確にしています。 人々がドキュメントを読まない場合、それは彼ら自身の問題です。 人々は「ストリーム」に激しく反応しておらず、「ああ、でも、それがすでに同じ名前を持っているので、人々がそれを小さな川だと思ったらどうなるだろう!」のようにナンセンスを言っています。 いいえ。
@Serentty @Entomyどちらも、実際のUnicodeの概念である「拡張書記素クラスター」を公開するStringInfo
クラスに興味があるかもしれません。 StringInfo
タイプはかなり古く、その結果、Unicode標準の非常に古いバージョンを実装していますが、 UAX#29、Secに準拠するように更新するための活発な作業があります。
はい、正確ではありませんが、大まかに十分に近いためです。
構成された表現と分解された表現の問題は、これを真実ではないと思います。 あらゆる種類のコンピューティング関連の定義とは対照的に、ここで書記素の言語学的定義を使用する場合、한と한はまったく同じ書記素のシーケンスです(3つのハングルジャモはセグメントHANとして音節_han_を表します)。ただし、最初のコードポイントは1つのコードポイントのみですが、2番目のコードポイントは3つのシーケンスです。
フィールドには独自の用語があり、単一のフィールド内に矛盾がない限り、それは問題ではありません。
これはまさに私のポイントでもあります。 Unicodeは独自の用語を使用する非常に複雑なシステムです。それでは、Unicodeが正確に整列していないのに、なぜある種の中途半端な「直感的な」用語を強制しようとするのでしょうか。 コードポイントはコードポイントです。 それらには言語的な類似点がなく、75%の精度で直感的に実行しようとすることは、C#がまだ回復しようとしているのと同じ種類の災害のレシピです。
あなたは非常に厳密なセマンティクスを主張しているので、UNICODEが「書記素クラスター」と呼ぶものは、言語学では単一の書記素にすぎないことがよくあります。
標準では、クラスターは単一の書記素のみで構成できます。 ここでは何も問題はありません。 _cluster_は、テキスト選択とカーソル移動の単位です。
名前が大したことではないと思います。 Msdocsは、ルーンが要約に含まれていることを明確にしています。 人々がドキュメントを読まない場合、それは彼ら自身の問題です。
これは、悪い設計上の決定を擁護するために繰り返し出てくる「プログラマーはより賢くなければならない」という議論です。 プログラマーがドキュメントを読んで、とにかくルーンがUnicodeコードポイントであることを学ぶ必要がある場合、そもそもそれをより「直感的な」名前と呼ぶポイントは何でしょうか。 ここでの議論は、「コードポイント」は紛らわしいため、より直感的な名前を選択するのが理にかなっているようですが、名前が誤解を招く問題に直面した場合、プログラマーはとにかくコードポイントが何であるかを知っている必要があります。ドキュメントを読むことから。 その場合は、タイプCodePoint
を呼び出して、プログラマーが検索して学習しやすくするのはなぜですか? これはすべて、.NETドキュメントがそもそもUnicodeに関してかなりひどいという問題を脇に置いており、「16ビットUnicode文字」の世界では代理ペアを後付けとして扱います。
これは、悪い設計上の決定を擁護するために繰り返し出てくる「プログラマーはより賢くなければならない」という議論です。
私はこれを言ったことはありません。
ここでの議論は、「コードポイント」が混乱しているということのようです
私もこれを言ったことはありません。
人々は「ストリーム」に激しく反応しておらず、「ああ、でも、それがすでに同じ名前を持っているので、人々がそれを小さな川だと思ったらどうなるだろう!」のようにナンセンスを言っています。 いいえ。
プログラマーは、 Stream
が小さな川ではないことを知っているのと同じように、 Rune
が特にルーン文字であるとは思わないほど賢いと言っています。
これを繰り返しましょう
私は、プログラマーはこれを理解するのに十分賢いと言っています。 あなたは私の口に言葉を入れています。
名前が大したことではないと思います。 Msdocsは、ルーンが要約に含まれていることを明確にしています。 人々がドキュメントを読まない場合、それは彼ら自身の問題です。
これが私がここで言及していることです。 「ルーン」という名前を支持する議論は、直観と書記素の概念との直観的なつながりに基づいています。 あなた自身は、2つが問題ではないほど密接に並んでいると主張していました。 その直感が間違っていて、対応が非常に悪い可能性があることをすべて指摘したとき、プログラマーはとにかくドキュメントを読む必要があるので、基本的には問題ではないという回答でした。 これが私が「プログラマーはもっと賢くなければならない」という意味です。 レガシーな理由がない場合、ドキュメントは誤解を招く名前の言い訳にはなりません。
プログラマーは、
Stream
が小さな川ではないことを知っているのと同じように、Rune
が特にルーン文字であるとは思わないほど賢いと言っています。
ここでの私の議論は、人々がそれをルーンルーンと混同するということではありません。 私の主張は、人々はそれをグリフ、書記素、および書記素クラスターと混同するだろうということです。これらはすべて、あなたの主張にもかかわらず、コードポイントと非常に悪い相関関係にあります。
私は、プログラマーはこれを理解するのに十分賢いと言っています。 あなたは私の口に言葉を入れています。
確かに、彼らが実際のゲルマンのルーン文字ではないことを理解するのに十分賢いです。 しかし、それらがグリフ、書記素、または書記素クラスターではないことを理解するには? ほとんどのソフトウェアのUnicode処理の品質に関する私の実際の経験は、ノーと言っています。
人々がドキュメントを読まない場合、それは彼ら自身の問題です。
はい、私はこれを支持します。 知性の欠如の問題としてではなく、むしろ急いで仮定する傾向の問題として。
プログラマーがString
が糸のねじれから作られた強くて細いロープを意味すると仮定した場合、そうです、それはString
という名前の問題とは見なされないことを意味します。 。
プログラマーがChar
が木炭などの焦げた材料、または特定の種類のマスを意味すると想定した場合、それはChar
という名前の問題とは見なされません。
プログラマーがcharacter
がストーリーテリングで使用される一連の精神的および倫理的特性の描写を意味すると想定する場合、それはcharacter
という名前の問題とは見なされません。
これらはすべてテキスト/言語の問題であることに注意してください。 それらはすべて他の意味を持っています。 それでも、プログラマーはうまく順応しています。 これらの用語は、この分野で確立された慣習、つまり私たちの用語のために、事実上の標準になっています。 プログラマーはこれに沿って従うのに十分賢いという前例が確立されています。
あなた自身は、2つが問題ではないほど密接に並んでいると主張していました。
はい、これはGitHubです。 すでにクローズされた問題について、名前にいくつかの確立された前例があったので、なぜRune
が大丈夫だと感じたのかについての考えを追加していました。 これは、広範な定義と慎重に選択された単語で満たされた論文を書く場所でも文脈でもありません。 たとえば、UTF-8デコーダーのPRを行う場合、代替アプローチでHoehrmannDFAを実装した理由を明示的に説明するつもりはありません。 「これが、これが機能する証拠です。これが、私がこれを採用した理由を裏付けるいくつかのベンチマークです」と言うつもりです。
私の主張は、人々はそれをグリフ、書記素、書記素クラスターと混同するだろうということです
前述のいずれも混乱していません。また、 Tree
、 Heap
、 Table
、 Key
、 Socket
、 Port
..。
これは非常に不誠実な議論です。 スレッドの一部とテキストの文字列は簡単に混同されません。 背の高い植物と木のデータ構造は簡単に混同されません。 一方、コードポイントは、ほとんどのプログラマーにとって非常によく理解されていない概念であり、これまでに説明した他のすべての概念と常に混同されています。 これに対する解決策は、あなたが言うように、ドキュメントを読むことです。 ただし、コードポイントに独自の「巧妙な」名前を使用する言語では、_実際のUnicodeドキュメント_からの知識をその言語に適用することがさらに困難になります。 そしてそれは私にこれをもたらします:
これらの用語は、この分野で確立された慣習、つまり私たちの用語のために、事実上の標準になっています。
そして、これがすべての核心です。 あなたは、「ルーン」がプログラミングで広く理解されているコードポイントの確立された用語であるか、そうであるべきであると主張しているようです。 前者の場合は、Go以外の主要なプログラミング言語を経験した平均的なプログラマーに聞いたことがあるかどうか尋ねてみてください。 後者の場合は、経験豊富な開発者でさえしばしば誤解されている、すでに混乱していてよく理解されていない状況で、公式のUnicode用語と競合する点をお聞きします。
@Entomy部外者の入力:私が知る限り、あなたの議論全体は「紛らわしくて悪いです、はい、しかしそれはそれほど紛らわしくて悪いことではありません」です。
それで? なぜそれは実際に代わりに良いことができないのですか? Unicodeの名前とまったく同じ名前を付けることの問題は何ですか?
また、ルーンは、コンピューティングの一般的な分野では、コードポイントではなく、書記素やクラスターでもありません。 Googleで「Unicodeルーン」を検索すると、それらをコードポイントに関連付けるものは、2ページ目まで表示されません。それでも、それは単にgodoc/Nimリンクです。 プログラマーがより快適かもしれないDuckDuckGoでも、それでも2ページ目の結果です。 したがって、私が見た名前に残された唯一の議論は、それがコードポイントを表すことは直感的であるということですが、そうではありません。 それが書記素クラスター、またはおそらく単なる書記素を表すことは直感的です。
出典:私はGoを使用しましたが、4年後、この号を今読んだときまでは書記素だと思っていました。
(そして、「十分に近い」ので書記素を示唆しても大丈夫だと言うと、16ビット文字が十分に近いことを思い出します。)
はい、プログラマーが賢く、より多くのドキュメントを読んでいれば、意味のある名前やタイプさえも必要ありません。 人々は、charの代わりにintの周りにコードポイントを渡すことを知っているでしょう。 しかし、そうではありません。 それらは現在と同じくらい賢く、YetAnotherAPIが追加されたからといってそれが変わることはありません。 目標は、英語以外の言語を正しく処理するソフトウェアの量を増やすことです。同じことを行うための新しい方法を導入し、以前と同じ参入障壁を維持するだけではありません。
議論のために、そして科学的な目的のために、ここで私はここにいるすべての人に、Unicodeテキスト処理を最もよく行う1つのプログラミング言語を紹介したいと思います。単純さを偽造することによって: Swift
String
は、任意のUnicodeテキストのバッファです。Character
は、繰り返し処理しますが、単一のUnicodeスカラー値ではなく、拡張書記素クラスターです。 書記素クラスターについては、この例を参照してください한
: let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
UnicodeScalar
と呼ばれます。UInt 8
とUInt 16
を生成することもできます。さて、私はここでC#が完全なSwiftスタイルになることを提案していません。 これは驚くべきことですが、非常に多くの変更と作業が必要です。 ただし、 @ Serenttyが指摘したすべての理由から、Swiftスタイルの命名を選択することを提案し、最終的にテキスト文字列をSwiftスタイルに変換するオプションを開いたままにしておきます。
Rune
よりも優れている可能性のある名前: CodeUnit32
、 UnicodeScalar
、 CodeUnit
、 UniScalar
、 UnicodeValue
、 UniValue
、 UnicodeScalarValue
。 最初の2つは、C#の命名規則にうまく適合していると思います。 コードユニットはUnicodeスカラー値をUnicode用語でエンコードするための単なる方法であるため、 UnicodeScalar
の方が客観的に適切な名前であることに注意してください。 したがって、 CodeUnit32
は、UTF-32でエンコードされたテキスト文字列のコード単位を反復処理することを意味しますが、 UnicodeScalar
はエンコードに依存しません。
編集:はい、名前System.Rune
はすでにそこにあります。 これはすべて、「これが5年前になる前に改善したい場合」にすぎません。
@pie-flavor
あなたの議論全体は、私が知る限り、「それは紛らわしくて悪いです、はい、しかしそれはそれほど紛らわしくて悪いことではありません」です。
いいえ、それは私の主張ではありません。 私は自分の障害に対して最善を尽くしていますが、これは私の意図したコミュニケーションではありません。
Googleで「Unicodeルーン」を検索すると、それらをコードポイントに関連付けるものは、2ページ目まで表示されません。それでも、それは単にgodoc/Nimリンクです。
Googleで「Unicode文字列」を検索しても、.NET文字列がどのように機能するかは具体的にわかりません。 これは、隣接するものを探すことです。 非常に厳密な例えとして、私は.NETとAdaの両方でプログラムします。 string
はそれらの間で同じではなく、それぞれを少し読むことをお勧めします。
オーバーロードされた定義は言語では珍しいことではありませんが、それでも私たちはうまく管理しています。 驚かれるかもしれませんが、「run」には少なくとも179の正式な定義があり、「take」には少なくとも127があり、「break」には少なくとも「123」があります。 [ソース]人々は驚くほど能力があり、ここで問題があると考えられているものよりもはるかに複雑なものをうまくナビゲートできます。 私の意見では、少なくとも2つの正式な定義を持つ「ルーン」の懸念は、人々が50倍を超える過負荷に対処することを示すことができる場合には保証されません。
さらに、これは検索エンジンの動作を大幅に悪用しています。 ほとんどの検索エンジンでは、何かにリンクしているページ数に基づいて結果が得られます。 他の要因もあり、アプローチごとに重みが異なります。 .NET Runeは、比較するとかなり最近の概念であるため、それについて話すコンテンツははるかに少なくなり、それに到達するためにより多くのページが必要になります。 しかし、それはまた間違った検索ツールを使用しています。 文字列検索アルゴリズムの研究を見つけたい場合、過去数年間に何か新しいものが出てきたかどうかを確認するために、私はGoogleやDDGを検索しません。 Semantic Scholar、GoogleScholarなどが出発点として適しています。 同様に、.NET APIについて理解したい場合は、最初にMSDocsを検索します。 物理学/工学用語である「慣性モーメント」は、その名前が曖昧または誤解を招くものであると不満を言う場合、最初の数冊の本では、最も小さい番号から始めて、それに関する情報が見つからないため、名前を変更する必要があります。デューイ十進分類法を使用しているライブラリでは、「慣性モーメント」の命名に問題はありません。 私は明らかに間違った場所を見ています。
出典:私はGoを使用しましたが、4年後、この号を今読んだときまでは書記素だと思っていました。
Goのドキュメントとリリースノート、少なくとも見つけたものを調べましたが、あなたに同意する必要があります。 彼らはrune
が何であるかについて非常に曖昧であり、残念ながらrune
がどれほど大きいかについてさえ曖昧です。 Adaがデータ型の制約についても同様に曖昧であり、数年後にはお尻に食い込んでいるのを見てきたので、この曖昧さは後で問題を引き起こすと思います。
ただし、msdocsは非常に詳細で簡潔な説明で、はるかに優れた仕事をしていると言わなければなりません。
Unicodeスカラー値を表します([U + 0000..U+D7FF]を含む;または[U+E000..U + 10FFFF]を含む)。
そうは言っても、コメントはやや不足しており、 Rune
が存在する理由と、それをいつ使用したいかについての詳細が有益です(また、前述の簡単な説明よりも詳細な説明を行うのに適した場所です)。 。 そこでいくつかの改善を提案します。
@Evrey
議論のために、そして科学的な目的のために、ここにいるすべての人に、Unicodeテキスト処理を最もよく行う1つのプログラミング言語を紹介したいと思います。
これは意見です。 私が絶対に同意するもの。 Swiftは確かに最新のUNICODEをより適切に処理します。 しかし、これらの結果を確認する査読済みの再現性のある研究の引用がなければ、これは科学的な主張ではありません。
さて、私はここでC#が完全なSwiftスタイルになることを提案していません。 これは驚くべきことですが、非常に多くの変更と作業が必要です。
そして、既存のソフトウェアを壊してしまいます。
オプションを開いたままにして、テキスト文字列を最終的にSwiftスタイルに変更します。
そして、既存のソフトウェアを壊してしまいます。
はい、System.Runeという名前はすでに存在しています。 これはすべて、「これが5年前になる前に改善したい場合」にすぎません。
そして、既存のソフトウェアを壊してしまいます。
既存の名前に変更が加えられた場合の仮定として、 Rune
がすでに使用されている.NET Core 3.0 / 3.1を対象とする既存のソフトウェアをどのように提案しますか?後のターゲットランタイムで別の名前ですか?
そして、既存のソフトウェアを壊してしまいます。
先に述べたように、私は原理と理想主義の観点から議論しているだけです。 物事の現実はたくさん言及されています。 そのすべてにいくつかのニュアンスがありますが:
String
インターフェイスに加えて、列挙型のメソッドとタイプを追加するだけです。 System.Char
を書記素クラスタータイプに変更するような急進的なことを意味するのではありません。System.Char
のような既存の型名が別の型に転用される場合、そうです、それは大きな重大な変更になります。 そして、その時の無責任な変化。 私はあなたと一緒です。System.Rune
をSystem.UnicodeScalar
または名前が何であれ非推奨の型エイリアスに変えてください。 Rune
を使用するソフトウェアは、非推奨の注記を除いて違いに気付かず、新しいソフトウェアはより適切な名前の実際のタイプを使用できます。 そして、架空の4.0はRune
をドロップします。System.Char
はSystem.CodeUnit16
などのエイリアスに変換できます。System.GraphemeCluster
をミックスに追加することを意味します。ここで考えて食べ物を落とすだけです。 System.Rune
は、その目的には不適切なタイプ名ですが、以前の命名ステータスを実際に悪化させることはないと思います。 最終的に、すべてのUnicodeスカラーをエンコードできる適切な型ができたのは素晴らしいことだと思います。 ただし、Unicodeの処理と命名がより正確になる傾向を広める絶好の機会があると思います。 ここにいる誰もが自由に取っておける機会です。
みなさん、こんにちはSystem.Text.Rune
という名前は、出荷されたものであり、今後使用するものです。 Rune
UnicodeScalar
という名前を使用することについては、以前は重要な(そして熱狂的な!)議論がありましたが、最終的にRune
が勝ちました。 現時点では、チームは別の名前を選択するというアイデアを楽しんでいません。 そして、人々がこれに情熱を注いでいることを私は知っていますが、ここでの会話を監視し続けますが、最終的には、命名問題の訴訟を継続するために費やされたエネルギーは利益をもたらさないことに注意してください。
明確にするため、およびドキュメントによると、.NETのSystem.Text.Rune
タイプは、Unicodeスカラー値とまったく同じです。 これは、建設によって実施されます。 これにより、Goのrune
UnicodeScalar
タイプに類似したものになります。
Rune
ドキュメントに、そのユースケースと、.NETの他のテキスト処理APIおよびUnicodeの概念との関係を詳しく説明するセクションを追加する取り組みが進行中です。 追跡の問題はhttps://github.com/dotnet/docs/issues/15845にあります。 その追跡の問題からコンセプトドキュメントの現在のドラフトへのリンクもあります。
私にとって、 UnicodeScalar
の主な欠点は、型名の長さと型のデータサイズの間に大きな違いがあることです。 基本的に、それはint
であり、そのドメインにいくつかのギャップがあります。
ただし、使用法の冗長性は極端になります。
foreach (UnicodeScalar unicodeScalar in name.EnumerateUnicodeScalars())
{
// ... unicodeScalar contains 1 int
}
vs $#$ 4 $#$を超える同等のchar
string
(理想的には、分割値を含むのではなく全体の値であるため、 char
を超える新しいタイプを使用します)
foreach (char c in name)
{
// ... c contains 1 ushort
}
ルーンはタイプ名の冗長性の妥協点です。
foreach (Rune rune in name.EnumerateRunes())
{
// ... rune contains 1 int
}
@GrabYourPitchforks
こんにちは! 正直なところ、この議論に巻き込まれたのは、その船が出航したように見えるので、名前を変更する必要があることを.NETの人々に納得させようとしているからではなく、単に自分の意見を表明したかったからです。このスレッドの他の人はそれに同意しませんでした。 C#が長い間持っていた壊れた文字タイプとは対照的に、最終的に_real_文字タイプを持ち、その名前が完全にそれに続くものであるのは素晴らしいことだと思います。 簡潔さと正確さの間には大きなバランスがあることを理解しています。スイートスポットをCodePoint
あたりのどこかに配置したとはいえ、他の人が同意しない理由は理解しています。
しかし、繰り返しになりますが、.NETのUnicodeサポートの最新化に尽力してくれたことに感謝します。 これは、世界中の多くの人々に大きな違いをもたらすものです。
最も参考になるコメント
元の号で言ったので、また言います。 フレーズが気に入らないために標準の言うことを放棄すると、解決する以上に混乱します。Unicodeにルーンコードページがあるとすると、それはさらに混乱します。
名前が間違っています。