Runtime: Memperkenalkan System.Rune

Dibuat pada 16 Sep 2017  ·  106Komentar  ·  Sumber: dotnet/runtime

Terinspirasi dari diskusi di sini:

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

Salah satu tantangan yang dihadapi .NET dengan dukungan Unicode-nya adalah bahwa ia berakar pada desain yang saat ini sudah usang. Cara kami merepresentasikan karakter dalam .NET adalah dengan System.Char yang merupakan nilai 16-bit, yang tidak cukup untuk mewakili nilai Unicode.

Pengembang .NET perlu mempelajari tentang Pasangan Pengganti yang misterius:

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

Pengembang jarang menggunakan dukungan ini, sebagian besar karena mereka tidak cukup akrab dengan Unicode, dan apalagi apa yang ditawarkan .NET untuk mereka.

Saya mengusulkan agar kami memperkenalkan System.Rune yang didukung oleh bilangan bulat 32 bit dan yang sesuai dengan codePoint dan bahwa kami memunculkan di C# jenis rune yang setara menjadi alias untuk jenis ini.

rune akan menjadi pengganti pilihan untuk char dan berfungsi sebagai dasar untuk penanganan Unicode dan string yang tepat di .NET.

Adapun mengapa nama rune, inspirasinya berasal dari Go:

https://blog.golang.org/strings

Bagian "Kode poin, karakter, dan rune" memberikan penjelasan, versi singkatnya adalah:

"Titik kode" agak sulit, jadi Go memperkenalkan istilah yang lebih pendek untuk konsepnya: rune. Istilah ini muncul di perpustakaan dan kode sumber, dan artinya persis sama dengan "titik kode", dengan satu tambahan yang menarik.

Perbarui Saya sekarang memiliki implementasi System.Rune di sini:

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

Dengan API berikut:

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

Perbarui Masalah yang Diketahui

  • [x] Beberapa API di atas mengambil uint, perlu mengambil Rune.
  • [ ] Perlu menerapkan keluarga IComparable
  • [ ] RuneCount/RuneLen membutuhkan nama yang lebih baik, lihat dokumen (mungkin dibutuhkan Utf8Bytes?)
  • [ ] Di atas, API "ustring" merujuk ke API UTF8 saya, ini sebenarnya bukan bagian dari API, tetapi kita harus mempertimbangkan apakah ada gerbang ke System.String di beberapa di antaranya, atau ke Utf8String.
api-needs-work area-System.Runtime up-for-grabs

Komentar yang paling membantu

Saya mengatakannya dalam edisi asli dan akan mengatakannya lagi. Mengabaikan apa yang dikatakan standar karena Anda tidak menyukai frasa akan lebih membingungkan daripada yang akan dipecahkan, dan, mengingat ada halaman kode rune di Unicode, itu hanya lebih membingungkan.

Nama itu salah.

Semua 106 komentar

Apakah Anda mengharapkan representasi dalam memori menjadi string objek 32-bit, atau diterjemahkan dengan cepat? Bagaimana dengan memori dua kali lipat jika mantan? Apa dampak kinerja jika yang terakhir?

Apakah penamaan teknologi terkait Unicode setelah skrip yang didukung Unicode tertentu (dan teknologi untuk meningkatkan dukungan pesawat astral setelah skrip BMP, pada saat itu) adalah ide yang bagus?

Saya pikir proposalnya (dan mungkin perlu dibuat lebih eksplisit) adalah bahwa representasi string dalam memori tidak berubah sama sekali. Jenis Rune hanya mewakili titik kode 21-bit individu yang berbeda (disimpan sebagai int 32-bit). Metode yang mengacu pada poin kode berpotensi mengembalikan Rune sebagai gantinya. Agaknya ada beberapa fungsi di string yang memungkinkan Anda menghitung Rune .

Saya pikir ada beberapa poin jelas yang perlu kita sepakati untuk sesuatu seperti ini:

  1. Apakah ada nilai signifikan dalam membuat tipe Rune daripada menggunakan Int32 seperti yang dilakukan metode saat ini?
  2. Apakah kata "rune" sebenarnya pilihan yang bagus?

Untuk menjawab (1), saya pikir kita perlu deskripsi yang lebih lengkap tentang bagaimana Rune akan diekspos, metode apa yang akan menerima dan mengembalikannya, dll. Dan untuk menentukan apakah itu lebih baik daripada berurusan dengan Int32 sebagai gantinya.

Adapun (2), saya sendiri agak ragu. "Rune" adalah semacam kata esoteris dalam bahasa Inggris, dan memiliki beberapa konotasi yang tidak biasa untuk penggunaannya dalam konteks ini. Ada juga poin yang dibawa orang lain: itu bertabrakan dengan konsep Unicode lain. Ketika saya melakukan pencarian untuk "Unicode Rune", saya mendapatkan sebagian besar hasil untuk blok Runic Unicode, dan hanya beberapa dokumentasi bahasa Go.

char adalah setengah kata dan juga kata penuh; dan Anda harus memeriksa sekelilingnya untuk menentukan yang mana - seperti arus yang mewakili setengah huruf atau satu huruf penuh.

Mungkin System.character di mana selalu surat lengkap... :sunglasses:

char adalah representasi yang buruk dan bahkan untuk bahasa ascii/latin saja; munculnya emoji masih akan meresap; itu berarti char adalah cek dan mungkin cek berikutnya char type

@NickCraver di twitter

Sementara utf8 adalah pengkodean lebar variabel; jarang (jika ada?) bahwa pengguna ingin berurusan dengan setengah karakter; baik untuk utf8 dan utf32.

Tipe 32-bit akan bekerja dengan baik untuk enumerasi.

Lebih sulit adalah indexOf, Length dll untuk kinerja atau perspektif memori.

  1. byte array adalah representasi terbaik untuk format buram; misalnya menyimpan format dalam format aslinya atau format akhir (transfer file, memasang kawat, dll)
  2. byte array adalah representasi terbaik untuk bandwidth memori dan ukuran memori
  3. array byte konsisten dengan Posisi dan indexOf, Panjang dll dalam hal byte

Namun, ketika Anda mulai peduli tentang karakter yang sebenarnya, huruf besar, pemisahan karakter; memahami apa itu karakter, byte menjadi lebar variabel. Char tidak membuatnya lebih baik; itu menggandakan ukuran karakter terkecil; menyertakan lebih banyak karakter, tetapi lebarnya masih bervariasi.

Untuk ini, nilai 32bit mungkin sangat berguna dari perspektif kode pengguna. Namun itu memiliki masalah dengan posisi, panjang dan item sekunder (indexOf dll)

Saya sangat tertarik pada string ascii saja dan string utf8 "Implementasi String Ringkas" https://github.com/dotnet/coreclr/issues/7083; untuk pemrosesan cepat hanya string ascii

Namun, bertentangan dengan semua hal yang saya perdebatkan di sana ... Saya ingin tahu seperti apa representasi 32bit dari utf8? Posisi akan dipetakan ke posisi; mencari karakter akan secepat di ascii, item dalam ukuran asli, dll. Bagaimana cara menumpuk terhadap pemrosesan setiap byte atau karakter untuk menentukan ukurannya?

Konversi ke dan dari akan lebih mahal; jadi ini lebih merupakan format pemrosesan; daripada format penyimpanan.

@migueldeicaza seperti yang saya pahami dan Anda hanya mengacu pada perluasan format karakter tunggal dari karakter 16-bit ke 32-bit sehingga semua representasi terkandung dalam nilai; daripada kemungkinan setengah nilai - bukan format internal.

Namun hal-hal yang perlu dipertimbangkan (yaitu hubungan posisi, dan biaya pencarian, dll)

Selain: Swift juga menangani seluruh format karakter

Swift menyediakan beberapa cara berbeda untuk mengakses representasi string Unicode. Anda dapat mengulangi string dengan pernyataan for-in, untuk mengakses nilai Karakter individualnya sebagai klaster grafem yang diperluas Unicode. Proses ini dijelaskan dalam Bekerja dengan Karakter.

Atau, akses nilai String di salah satu dari tiga representasi yang sesuai dengan Unicode lainnya:

  • Kumpulan unit kode UTF-8 (diakses dengan properti utf8 string)
  • Kumpulan unit kode UTF-16 (diakses dengan properti utf16 string)
  • Kumpulan nilai skalar Unicode 21-bit, setara dengan bentuk penyandian UTF-32 string (diakses dengan properti unicodeScalars string)

Saya mengatakannya dalam edisi asli dan akan mengatakannya lagi. Mengabaikan apa yang dikatakan standar karena Anda tidak menyukai frasa akan lebih membingungkan daripada yang akan dipecahkan, dan, mengingat ada halaman kode rune di Unicode, itu hanya lebih membingungkan.

Nama itu salah.

@mellinoe

Rune akan menyediakan banyak operasi yang saat ini Anda harapkan pada Char, seperti ToLower[Invariant], ToUpper[Invariant], ToTitle, IsDigit, IsAlpha, IsGraphic, IsSymbol, IsControl.

Selain itu, itu akan memberikan hal-hal seperti:

  • EncodeRune (mengkodekan rune menjadi buffer byte)
  • RuneUtf8Len (mengembalikan jumlah byte yang diperlukan untuk mengkodekan rune dalam UTF8),
  • IsValid (tidak semua nilai Int32 valid)

Dan interop ke string, dan Utf8string sesuai kebutuhan.

Saya mem-porting/menyesuaikan dukungan string Go ke .NET, dan menawarkan tampilan seperti apa dunia ini (ini tanpa bantuan runtime):

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

@benaadams berkata:

Saya ingin tahu seperti apa representasi utf8 32bit? Posisi akan dipetakan ke posisi; mencari karakter akan secepat di ascii, item dalam ukuran asli, dll. Bagaimana cara menumpuk terhadap pemrosesan setiap byte atau karakter untuk menentukan ukurannya?

UTF8 adalah representasi dalam memori, yang akan terus ada dan akan terus menjadi representasi (dan mudah-mudahan, ini adalah pengkodean internal jangka panjang untuk string masa depan di .NET).

Anda akan memecahkan kode string UTF16 yang ada (System.String) atau string UTF8 yang akan datang (Utf8String) bukan menjadi Chars (untuk alasan yang Anda dan saya setujui), tetapi menjadi Rune.

Beberapa contoh, mengubah string Utf8 menjadi rune:

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

Apakah string utf8 berisi rune:

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

Saya baru menyadari bahwa saya tidak mengimplementasikan pengindeks ("Dapatkan saya rune ke-n")

Kecepatan akses ke Nth-rune dalam sebuah string adalah fungsi dari penyimpanan, bukan dari Rune itu sendiri. Misalnya, jika penyimpanan Anda adalah UTF32, Anda memiliki akses langsung ke setiap rune. Ini akademis, karena tidak ada yang menggunakannya. Akses ke elemen ke-N pada UTF16 dan UTF8 memerlukan pemindaian yang tepat dari elemen-elemen yang membentuk string (byte atau int 16-bit) untuk menentukan batas yang tepat. Jangan bingung dengan String[int n] { get; } yang hanya mengembalikan karakter ke-n, terlepas dari kebenarannya.

@benaadams Karakter Swift adalah level yang lebih tinggi dari rune. Karakter dalam swift adalah "klaster grafem yang diperluas" yang terdiri dari satu atau lebih rune yang ketika digabungkan menghasilkan karakter yang dapat dibaca manusia.

Jadi karakter Swift tidak memiliki ukuran 32-bit yang tetap, itu adalah panjang variabel (dan kita juga harus memiliki konstruksi itu, tetapi itu termasuk dalam tipe data yang berbeda). Berikut adalah contoh dari halaman itu, tetapi ini juga meluas ke pengaturan warna emoji:

Berikut ini contoh. Huruf é dapat direpresentasikan sebagai skalar Unicode tunggal é (HURUF KECIL LATIN E WITH ACUTE, atau U+00E9). Namun, huruf yang sama juga dapat direpresentasikan sebagai pasangan skalar—huruf standar e (Huruf KECIL LATIN E, atau U+0065), diikuti dengan KOMBINASI skalar AKSEN AKUT (U+0301). COMBINING ACUTE ACCENT scalar secara grafis diterapkan ke skalar yang mendahuluinya, mengubah e menjadi é ketika dirender oleh sistem rendering teks yang sadar Unicode.

Hanya bagi saya kata grapheme akan lebih menggambarkan diri sendiri.

Dua sen saya pada nama itu, mengutip lagi posting Go tentang string dengan penekanan:

" Poin kode " agak sulit, jadi Go memperkenalkan istilah yang lebih pendek untuk konsep: rune. Istilah ini muncul di perpustakaan dan kode sumber, dan artinya persis sama dengan "titik kode" , dengan satu tambahan yang menarik.

Saya 100% setuju dengan @blowdart , menyebutnya rune hanya membingungkan dan salah. Kode penyebutan standar unicode menunjuk tiga kali hanya di halaman pertama bab pendahuluan tetapi istilah rune tidak muncul di mana pun.

Jika itu adalah titik kode, maka itu harus diberi nama titik kode , sesederhana itu.

Jika istilah rune tidak pernah muncul dalam standar, mungkin tidak apa-apa, masalahnya muncul beberapa kali di bab 8, dalam kaitannya dengan rune. Ini bukan hanya salah, itu secara aktif membingungkan masalah ini dengan yang lain.

Hanya bagi saya kata grapheme akan lebih menggambarkan diri sendiri.

Jika ini tentang poin kode 32-bit, istilah grapheme akan membingungkan karena grafem adalah sesuatu yang lain lagi.

Saya sering menginginkan tipe data titik kode (tidak dalam waktu yang lama, karena apa yang telah saya kerjakan telah berubah, tetapi beberapa tahun yang lalu saya sangat menginginkan ini dan menulis solusi parsial yang tumpang tindih untuk bagian dari kebutuhan itu dan bisa dilakukan dengan perpustakaan yang sudah teruji). Saya tidak mengerti mengapa ini tidak boleh disebut sesuatu seperti CodePoint . Kebanyakan orang yang menyadari bahwa mereka membutuhkan tipe seperti itu kemungkinan besar akan berpikir dalam hal poin kode, bukan dalam hal rune; atau yang lain dalam hal kode-poin dan rune sebagai bagian terpisah dari tugas mereka. ᛒᛇᚦ ᛥᛁᛚᛖ /rúna béoþ stille bryceu/rune masih digunakan. Saya hanya perlu menggunakan rune sekitar setahun sekali, dan umumnya dengan perkamen dan tinta daripada apa pun yang digital, tetapi tentu saja ada orang yang menanganinya secara digital juga. (Bahkan dengan data abad ke-20, saya tahu kasus di mana mereka digunakan dalam pengarsipan data era Perang Dunia II).

Grapheme masih lebih rumit, karena orang sering ingin menggunakan oktet → karakter (sudah ditangani dengan baik oleh .NET) lalu karakter → poin kode, dan kemudian kode poin → graphem.

menandai ini sebagai up-for-grabs untuk saat ini.

Langkah Selanjutnya : Apa yang kami cari adalah: proposal formal yang akan menyertakan umpan balik dari atas (penamaan tipe sebenarnya, dan keuntungan menggunakan ini dibandingkan hanya menggunakan Int32).

Saya telah memperbarui masalah, baik dengan API yang diusulkan dan implementasi awal:

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

Adapun penamaan tipe, ini adalah masalah memiliki tempat di mana Anda dapat mencari operasi yang valid pada tipe tersebut, serta memiliki kemampuan khusus tipe (lihat implementasi untuk beberapa contoh).

@migueldeicaza sebelum menandainya sebagai siap untuk ditinjau, apa pendapat Anda tentang kekhawatiran tentang penamaan jenis yang sebenarnya, menurut Anda mungkin CodePoint mungkin lebih baik dalam hal menggambarkan apa jenisnya?

Saya pikir argumen untuk menggunakan codepoint sebagai nama lemah.

Menggunakannya adalah ide yang buruk, dalam jangka panjang, ini perlu mengganti setiap penggunaan "char" dalam kode yang ada - jika kami berharap mendapatkan dukungan Unicode yang tepat.

Saya berharap kami bisa menggunakan "char" seperti yang dilakukan Rust, tetapi sayangnya, kami sudah mengambilnya dan kami memiliki yang rusak.

Pergi setelah memeluk nama ini adalah preseden yang baik.

Saya setuju bahwa code point bukanlah istilah yang tepat untuk digunakan di sini. Paling tidak, berdasarkan standar Unicode tidak termasuk nilai di atas 10FFFF (http://unicode.org/glossary/#code_point).

Saya tidak suka istilah rune . Saya pikir ini sudah digunakan di Unicode dan di tempat lain yang hanya akan menyebabkan kebingungan secara keseluruhan. Saya juga berpikir itu memiliki peluang yang cukup bagus untuk bertentangan dengan tipe pengguna yang ada (terutama untuk hal-hal seperti Unity, di mana 'Rune' mungkin mewakili objek game tertentu).

Namun, saya menyukai ide tipe yang mencakup tipe C++ 11 char32_t , hanya dengan nama yang berbeda.

Ada sesuatu yang bisa dikatakan untuk Char32 . To the point, itu analog dengan nama tipe dari tipe integral. Ini berbicara pada tingkat konseptual karakter, daripada tingkat kode-poin. Itu bukan nama naskah.

Karena kita ingin memiliki nint bagaimana dengan nchar ?

Presedennya akan ada di database nchar dan nvarchar

Dimana nchar adalah karakter nasional / karakter nasional dan nvarchar adalah karakter nasional yang bervariasi / karakter nasional yang bervariasi; untuk jenis bidang mana Anda dapat menyimpan unicode, juga beberapa standar ISO - tidak yakin yang mana, mungkin SQL?

Apa penggunaan rune Unicode ini? Itu adalah berita bagi saya.

U+16A0 ke U+16F8

Ini digunakan untuk merujuk ke halaman kode tertentu dalam standar Unicode. Itu telah diangkat beberapa kali di utas ini: http://unicode.org/charts/PDF/U16A0.pdf

Ah rahasia, bukan rune.

Nama backing (System.Rune atau System.Char32) tidak sepenting label yang akan diproyeksikan ke C#.

Pertama: ya, ya, dan lebih dari ini tolong. Saya suka ide ini (sejujurnya, saya sudah memiliki ide yang sama untuk waktu yang lama sekarang). Sebenarnya kami telah menggunakan kelas string khusus dan struct karakter dalam kompatibilitas Git kami nanti di Visual Studio untuk sementara waktu sekarang (Git berbicara dalam Utf-8 dan mentranskode semuanya sangat lambat).

Pada topik nama metode statis, bisakah kita menghindari pemberian nama pendek yang sewenang-wenang? Mengingat Char.IsPunctuation adalah metode saat ini, dapatkah kita mencerminkannya dengan Rune.IsPunctuation atau yang serupa?

Dengan asumsi (selalu berbahaya) bahwa ini diterima, dapatkah kita memiliki rune atau c32 intrinsik, atau hanya mengganti char sepenuhnya dengan implementasi System.Rune ?

Saya menyarankan unichar atau uchar meskipun uchar akan terlihat seperti karakter yang tidak ditandatangani. Apapun yang dipilih, saya berharap kita mendapatkan alias khusus bahasa untuk itu. Saya pribadi adalah penggemar berat menggunakan alias bahasa untuk tipe primitif.

Saya juga setuju dengan @whoisj - Pasti lebih suka nama metode lengkap daripada singkatan/pendek.

Saya juga setuju dengan @whoisj - Pasti lebih suka nama metode lengkap daripada singkatan/pendek.

IMO bahasa (dan perpustakaannya) perlu memilih nama lengkap yang disingkat, atau menggunakan singkatan (seperti C dengan strcmp, memcpy, dll.)

atau cukup ganti char sepenuhnya dengan implementasi System.Rune ?

Itu akan menjadi perubahan besar karena alasan yang cukup jelas.

Itu akan menjadi perubahan besar karena alasan yang cukup jelas.

Komentar saya sebagian besar lidah dan pipi, dan penuh harapan. Tipe 16-bit untuk karakter adalah kesalahan sejak awal.

Tangkapan yang bagus pada penamaan, akan diperbaiki.

Ada inkonsistensi kecil lainnya di API yang disediakan, kami juga akan memperbaikinya.

@migueldeicaza

Ah rahasia, bukan rune.

Runic adalah kata sifat, rune adalah kata benda. Semua karakter rahasia adalah rune.

_Runic_ adalah kata sifat, _rune_ kata benda. Semua karakter rahasia adalah rune.

Adil seperti yang terlihat "Cortana: define _'rune'_" muncul dengan:

surat alfabet Jermanik kuno, terkait dengan alfabet Romawi.

Ah ya, setiap kali saya melihat kata "rune", saya langsung memikirkan bab yang tidak jelas ini pada spesifikasi yang belum pernah dibaca siapa pun yang berbicara tentang "The Runic Unicode Block".

Saya memikirkan kenangan masa kecil membaca Tolkien.

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

Ya, saya tidak secara khusus memikirkan spesifikasinya, tetapi saya memikirkan jenis karakter yang dirujuk oleh spesifikasi tersebut.

Anda mengatakan rune dan saya memikirkan sihir, fantasi, teka-teki samar, bahasa kuno, dll.

Saya senang Anda tidak melihat kata "rune" dan langsung berpikir "Ah ini jelas mengacu pada blok rahasia Unicode 7.0 yang nilainya akan dibatasi pada nilai unik tersebut dalam kisaran 16A0..16F8".

Saya tahu bahwa Tanner adalah satu suara di sini, dan beberapa dari Anda masih berpikir "Tapi Miguel, saya melihat kata 'rune' dan saya langsung memikirkan tipe data yang hanya bisa menampung 88 kemungkinan nilai". Jika ini adalah masalah yang Anda perjuangkan, saudara/saudari saya, saya punya berita untuk Anda: Anda punya ikan yang lebih besar untuk digoreng.

Saya telah mengikuti utas ini untuk sementara waktu dengan campuran kegembiraan dan keraguan selama lebih dari sebulan. Saya menghadiri Konferensi Internasionalisasi dan Unicode bulan lalu, dan tidak ada presentasi yang berhubungan dengan .NET. Ada masalah persepsi dengan .NET Framework; salah satu yang belum tentu diterima dengan susah payah mengingat sejarah fitur globalisasinya. Karena itu, saya suka pemrograman dalam C# dan benar-benar ingin melihat fitur-fitur baru yang memperkuat tempat .NET dalam komunitas yang benar-benar global. Saya pikir proposal ini adalah langkah yang baik ke arah itu untuk merangkul standar yang diharapkan komunitas internasionalisasi dari perangkat lunak.

Keragu-raguan saya sebagian besar karena pertengkaran tentang nama tipe. Meskipun benar bahwa desainer Go memilih nama "rune", itu bermasalah karena alasan yang disebutkan di atas berulang kali: ada poin kode yang disebut rune dengan tepat. Sulit bagi saya untuk setuju dengan proposal yang mencoba untuk mendekati standar yang dihormati, dan kemudian mendefinisikan kembali terminologi yang merupakan bagian dari spesifikasi. Lebih jauh lagi, argumen bahwa sebagian besar pengembang tidak mengetahui istilah tersebut adalah palsu karena pengembang yang paling tertarik untuk menggunakan jenis ini dengan benar lebih mungkin untuk memahami spesifikasi Unicode dan memiliki gagasan yang baik tentang apa sebenarnya "rune". Bayangkan keanehan yang mungkin ada jika Anda mencampuradukkan terminologi:

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

Tentu saja, saya telah mengambil jalan yang mudah di sini, mengkritik tanpa memberikan nama baru. Saya pikir saran CodePoint sebelumnya adalah opsi yang paling deskriptif (dan itu muncul dalam deskripsi masalah asli), tetapi char32 akan memiliki lebih banyak paritas dengan tipe primitif yang ada (walaupun saya akan ragu untuk mengatakan bahwa tidak setiap titik kode adalah karakter). Jika tujuannya adalah membangun dukungan Unicode yang lebih baik ke .NET, saya benar-benar mendukung jalan itu, tetapi cara terbaik untuk melakukannya adalah dengan mengikuti spesifikasi.

Tiga saran:

  1. Kelas Rune tidak memiliki "IsCombining" yang kritis. Tanpa itu, kita tidak dapat mengubah dari serangkaian rune (titik kode) menjadi serangkaian grafem.
  1. Saya juga ingin memiliki kelas Grapheme yang sesuai. Sebuah grafem dalam konteks ini benar-benar hanya daftar satu atau lebih Rune (Code Points) sehingga rune pertama tidak digabungkan dan rune lainnya digabungkan. Kasus penggunaan adalah ketika pengembang perlu berurusan dengan potongan "karakter yang terlihat". Misalnya, a + GRAVE adalah dua rune yang membentuk satu grafem.

  2. Dalam jaringan kita sering mendapatkan sebongkah byte yang perlu kita ubah menjadi objek seperti "string" di mana byte mungkin tidak lengkap (misalnya, kita diberitahu tentang beberapa byte, tetapi byte terakhir dalam urutan multi-byte belum belum cukup tiba). Saya tidak melihat cara yang jelas untuk mengubah aliran byte menjadi aliran rune sehingga kehilangan byte terakhir dari urutan multi-byte dianggap sebagai situasi normal yang akan diperbaiki ketika kita mendapatkan set byte berikutnya.

Dan terakhir, silakan gunakan nama Unicode dan sebut ini sebagai CodePoint. Ya, konsorsium Unicode melakukan pekerjaan yang buruk dalam menjelaskan perbedaannya. Tetapi solusinya adalah dengan menambahkan dokumentasi yang jelas dan berguna; hal lain membingungkan masalah alih-alih membantu mengklarifikasi.

Saya tidak tahu harus mulai dari mana untuk permintaan penggabungan, baik Go, Rust, atau Swift memunculkan API semacam itu pada rune, Character, atau Unicode Scalar (nama mereka untuk System.Rune ). Harap berikan implementasi yang diusulkan.

Pada klaster grafem, sebaiknya dilacak secara independen dari System.Rune . Untuk apa nilainya, Swift menggunakan Character untuk ini, tetapi juga Swift bukan model yang bagus untuk menangani string.

Mengubah aliran byte menjadi rune yang tepat adalah masalah yang dimiliki oleh API tingkat yang lebih tinggi. Karena itu, Anda dapat melihat implementasi ustring saya yang menggunakan substrat yang sama dengan implementasi System.Rune saya untuk melihat bagaimana buffer ini dipetakan ke dalam string utf8:

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

Dokumentasi, yang belum saya perbarui sejak saya memperkenalkan System.Rune ke dalam API, tetapi mencakupnya:

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

Untuk penamaan, jelas Rust adalah yang terbaik dengan char , tapi kami mengacaukannya. Yang terbaik kedua adalah Pergi dengan rune . Apa pun yang lebih besar dari empat karakter hanya akan mengganggu orang untuk melakukan hal yang benar.

Saya minta maaf; Saya pikir CodePoint adalah nama yang luar biasa bagus. Cukup jelas, mudah diingat, dan dilengkapi secara otomatis dengan c p .

IsCombining pasti diperlukan, tetapi begitu juga mengetahui kelas penggabungan dan begitu kita memilikinya IsCombining sebagian besar adalah gula karena hanya IsCombining => CombiningClass != 0 atau IsCombining => CombiningClass != CombiningClass.None . Cluster grapheme memang akan berada di luarnya lagi, tetapi titik awalnya adalah mengetahui kelas kombinasi untuk pengelompokan default, penataan ulang, dll.

CodePoint adalah nama yang bagus untuk tipe tentang poin kode, dan empat karakter bukanlah batasan yang harus kita tangani dengan tipe lain yang banyak digunakan; string 50% lebih besar dan tidak mencegah kami menggunakannya secara teratur. Empat huruf yang dipilih secara acak akan menjadi nama yang lebih baik daripada mengulangi kesalahan Go.

Karena uint tidak sesuai dengan CLS, tidak ada ctor yang sesuai dengan CLS yang mencakup bidang astral. int akan diperlukan juga.

Konversi implisit dua arah dapat menyebabkan hal buruk terjadi dengan kelebihan beban, jadi satu arah mungkin harus eksplisit. Tidak jelas yang mana. Di satu sisi uint / int lebih lebar dari titik kode karena nilai di bawah 0 atau di atas 10FFFF 16 tidak berarti, dan konversi implisit memungkinkan penggunaan lebih cepat dari lebih banyak API yang ada untuk angka. Di sisi lain, saya dapat melihat keinginan untuk melakukan cast dari nomor ke titik kode lebih sering daripada sebaliknya.

Karena uint tidak sesuai dengan CLS, tidak ada ctor yang sesuai dengan CLS yang mencakup bidang astral. int akan diperlukan juga.

Itu kecuali jenis intrinsik baru diperkenalkan ke dalam bahasa umum.

JonHanna -- maksud Anda ketiga konstruktor ini:
uint operator implisit statis publik (Rune rune);
Rune operator implisit statis publik (char ch);
Rune operator implisit statis publik (nilai uint);

harus "int" bukan "uint". AFAICT, int dengan mudah mencakup seluruh set pesawat astral (non-BMP).

@PeterSmithRedmond Maksud saya selain dua konstruktor, satu mengambil char dan satu mengambil uint , harus ada yang mengambil int , tapi ya juga harus ada int operator konversi (apa yang seharusnya implicit dan apa explicit adalah pertanyaan lain). Tidak ada salahnya memiliki uint juga untuk bahasa yang dapat menggunakannya; itu pertandingan yang cukup alami.

Jika ini harus menggantikan System.Char harus dimungkinkan untuk melakukan "aritmatika" di atasnya (yaitu ==, !=, >, < tidak yakin pada +, -, *, /) dan yang lebih penting harus mendukung literal ini ketik misalnya saya harus bisa menulis:

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


image

Jika tidak rune , hanya sinonim lain dari character yang dapat bekerja mungkin letter ?

kata benda

  1. komunikasi tertulis atau cetak yang ditujukan kepada seseorang atau organisasi dan biasanya dikirimkan melalui surat.
  2. simbol atau karakter yang secara konvensional digunakan dalam menulis dan mencetak untuk mewakili suara ucapan dan itu adalah bagian dari alfabet.
  3. sepotong jenis pencetakan bantalan simbol atau karakter tersebut.

Meskipun itu akan bertentangan dengan huruf vs angka

Huruf memiliki arti yang lebih tepat dalam unicode (dan Net pada umumnya) daripada rune.

Saya pikir, jika kita akan membuat tipe karakter Unicode ini, kita harus mengikuti konvensi penamaan Unicode; yang berarti _"titik kode"_.

Poin Kode . (1) Nilai apa pun dalam ruang kode Unicode; yaitu, kisaran bilangan bulat dari 0 hingga 10FFFF16. (Lihat definisi D10 di Bagian 3.4, Karakter dan Pengkodean .) Tidak semua titik kode ditetapkan ke karakter yang dikodekan. Lihat jenis titik kode . (2) Nilai, atau posisi, untuk karakter, dalam set karakter berkode apa pun.

Atau mungkin kita menyerah begitu saja dan menyebut bebek sebagai "bebek" dan menyebutnya sebagai Karakter Unicode (alias uchar ).

Mengapa tidak menyelesaikan ini untuk menggunakan System.CodePoint saja?
Imho itu lebih tepat dalam hal terminologi dari Unicode, dan orang lain di dunia Java menggunakannya. Jadi alih-alih memiliki istilah sendiri, mari kita patuhi persyaratan Unicode. Lebih masuk akal, dan lebih universal dalam hal karakter umum dan implementasi string di .NET, juga mengetahui fakta bahwa String di .NET adalah kumpulan char, dan kumpulan char ini berbasis Unicode.

Saya tahu, karena saya pernah tinggal di dunia Java dan .NET.
Dan mungkin mari kita mulai membuat draft implementasi ini.

Sungguh ada dua komponen ini dan keduanya akan diperlukan (CodeUnit di https://github.com/dotnet/corefxlab/issues/1799 oleh @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 penting untuk mewakili pengkodean lebar variabel dan untuk digunakan dalam Span<ubyte> untuk memastikan api teks tersedia pada jenis teks tetapi bukan byte mentah.

CodePoint / uchar penting untuk pemrosesan yang masuk akal; misalnya .IndexOf(❤) sebagai ubyte dengan sendirinya tidak dapat digunakan untuk mencari karakter unicode multibyte; dan menghitung lebih dari ubyte s akan penuh dengan bahaya, jadi enumerator harus bekerja dalam unit uchar .

Menggabungkan dua proposal itu akan menjadi sesuatu seperti

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

Saya telah menggunakan UnicodeScalar dalam implementasi prototipe saya untuk merujuk ke nilai skalar Unicode (nilai dalam kisaran U+0000..U+10FFFF, inklusif; tidak termasuk poin kode pengganti) dan Utf8Char untuk merujuk ke unit kode UTF-8. Sepertinya banyak orang lebih suka _Rune_ daripada _UnicodeScalar_ karena kurang seteguk. Saya tidak terlalu peduli, tetapi saya akan menunjukkan bahwa istilah "Nilai skalar Unicode" adalah istilah yang sama yang digunakan oleh spesifikasi Unicode . ;)

.NET Framework juga memiliki konsep "elemen teks", yang merupakan satu atau lebih skalar yang bila digabungkan membuat grafem tunggal yang tidak dapat dibagi. Info lebih lanjut tentang ini di MSDN . Khususnya, ketika Anda menghitung string, Anda mungkin ingin menghitung dengan unit kode ( Utf8Char atau Char ), nilai skalar ( UnicodeScalar ), atau elemen teks, tergantung pada Anda skenario tertentu. Idealnya kami mendukung ketiga jenis di kedua String dan Utf8String.

Permukaan API untuk prototipe kami belum selesai dan dapat berubah dengan cepat, tetapi Anda dapat melihat beberapa pemikiran saat ini di https://github.com/dotnet/corefxlab/tree/utf8string/src/System.Text.Utf8/System /Teks dan https://github.com/dotnet/corefxlab/blob/master/src/System.Text.Primitives/System/Text/Encoders/Utf8Utility.cs.

Sedikit di luar topik:
Haruskah "elemen teks" menjadi segmentasi yang ditentukan oleh "Batas Cluster Grapheme" di 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());
        }
    }
}

Hasil yang diharapkan:
👩🏻👦🏼.
👨🏽👦🏾👦🏿.
👩🏼👨🏽👦🏼👧🏽.
👩🏻👩🏿👧🏼👧🏾.

hasil sebenarnya:
👩.
🏻.
Lalai
👦.
🏼.
👨.
🏽.
Lalai
👦.
🏾.
Lalai
👦.
🏿.
👩.
🏼.
Lalai
👨.
🏽.
Lalai
👦.
🏼.
Lalai
👧.
🏽.
👩.
🏻.
Lalai
👩.
🏿.
Lalai
👧.
🏼.
Lalai
👧.
🏾.

UnicodeScalar masih sangat mudah untuk diketik. u s c Spasi (pelengkapan otomatis) Karena itu adalah istilah yang paling tepat dan paling menggambarkan diri sendiri, saya sangat berharap kita mendapatkannya.

@ufcpp Itu poin yang bagus. Jangan ragu untuk membuka masalah baru untuk itu. Jika kami tidak dapat mengubah perilaku karena alasan kompatibilitas, saya sarankan agar kami tidak menggunakan tipe itu dan membuat pencacah graf yang sesuai dengan spesifikasi.

ubyte / uchar membingungkan. Mereka membaca seperti unsigned char / unsigned byte diberikan konvensi yang ditetapkan dengan ushort / uint / ulong . Mungkin char8 / u8char dan char32 / u32char lebih jelas?

Bagaimanapun, saya pikir kami tidak selaras tentang apakah unit kode & poin kode UTF-8 adalah:

  1. tipe data primitif tingkat rendah di .NET - seperti byte , int
  2. format data untuk dikonversi ke/dari primitif yang ada - seperti DateTime , Guid

Dan kemudian, bagaimana kami mengekspos API terkait codepoint dengan keputusan itu?

Opsi 1 berarti menangani teks melalui char8, char16, dan char32 primitif (dan menyertai u8string, u16string, dan u32string) seperti C++17. Kemudian char32 as rune adalah nama yang buruk, mengingat kita sudah memiliki char16 sebagai char dan membutuhkan nama ke-3 untuk char8 juga.

Opsi 2 berarti byte dan int/uint 'cukup baik' untuk menyimpan unit kode & titik kode UTF. Ini menyiratkan semua string tetap UTF-16. CodePoint / rune memecahkan masalah Code Point semantik daripada representasi biner - dan tidak dimaksudkan untuk IO .

IMO UTF-8/UTF-32 hanyalah format data (opsi 2). Perlakukan mereka sebagai data (byte/int). CodePoint lebih mirip DateTime atau Guid (pengidentifikasi lain*) daripada int bagi saya - bukan tipe primitif tingkat rendah, tidak didukung secara langsung di IO (yaitu BinaryWriter), tidak perlu intrinsik.

@miyu Prototipe yang kami bawa di corefxlab lebih dekat ke Opsi 1. Ada tipe data khusus untuk mewakili unit kode, dan tipe data ini untuk representasi internal data tekstual dan tidak dapat digunakan untuk mengirimkan data tekstual melalui kabel. (Seperti yang Anda tunjukkan, .NET sudah bekerja seperti ini hari ini: System.Char adalah unit kode dari string UTF-16, tetapi System.Char tidak dapat dikirim melalui kabel.)

Selain itu, ada API untuk mengkonversi antara byte[] / Span<byte> / dll. (ini adalah representasi biner dari semua data dan sesuai untuk I/O) dan tipe primitif seperti Utf8String / String / Guid / dll. Beberapa di antaranya lebih lugas daripada yang lain. Sebagai contoh, kita dapat mengekspos properti Utf8String.Bytes yang mengembalikan ReadOnlySpan<byte> untuk digunakan dalam i/o, dan pengambil properti ini dapat memiliki kompleksitas O(1). Kami tidak akan memperkenalkan properti seperti itu pada tipe String , meskipun Anda dapat membayangkan memiliki metode kenyamanan String.ToUtf8Bytes() . Dan meskipun akan ada properti Utf8String.Bytes , tipe elemen dari enumerasi pada instance Utf8String secara langsung tidak akan menjadi byte . Itu akan menjadi Utf8CodeUnit (nama TBD) atau UnicodeScalar , mana saja yang menurut kami lebih masuk akal untuk jenis aplikasi yang ingin dibuat oleh pengembang.

Ide yang konyol - bagaimana dengan wchar (_wide char_)? Saat ini, sebagian besar lingkungan kompiler C dan C++ (di luar Windows) sudah menggunakan wchar_t untuk mewakili fungsi yang setara dengan unit kode 32-bit. Windows adalah pengecualian penting, di mana wchar_t didefinisikan sebagai tipe 16-bit, tetapi pengembang yang p/memanggil di Windows hari ini harus menyadari perbedaan lebar bit antara .NET char dan gaya-C char .

Jenis / kata kunci wchar akan melanggar konvensi penamaan kami, tetapi hanya membuangnya sebagai pertimbangan.

Ide konyol dari dinding - bagaimana dengan wchar (karakter lebar)?

Bekerja untuk saya

Jenis / kata kunci wchar akan melanggar konvensi penamaan kami, ...

Sepertinya kita tidak akan mendapatkan kata kunci bahasa C# singkat

https://github.com/dotnet/apireviews/pull/64#discussion_r196962756 tampaknya sangat tidak mungkin bahwa kami akan memperkenalkan kata kunci bahasa untuk jenis ini karena ini harus kontekstual (yaitu tergantung pada apakah mereka dapat menyelesaikan ke jenis dengan nama kata kunci yang masih harus mereka ikat ke jenis itu, bukan jenis yang diwakili oleh kata kunci).

Jadi jika kita menginginkan sesuatu yang bagus... yaitu NotLotsOfCapitalFullWords ...

Meskipun saya biasanya menyukai konvensi penamaan .NET, nama yang panjang sedikit menyinggung untuk int yang pada dasarnya juga akan digunakan dalam generik dan sebagai variabel loop.

misalnya tidak ada yang melakukannya

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

Apakah mereka? (Pasti...)

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

Jauh lebih buruk

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

Sepertinya baik-baik saja...

rune , wchar , dan uchar (disarankan di utas lain) semuanya terdengar bagus bagi saya. Adakah saran untuk rekan string ? wstring , ustring , atau lainnya?

... dan mengapa tidak mendapatkan kata kunci bahasa C#? Tentu, tidak memiliki satu untuk rilis pertama masuk akal, tetapi jika ini akan menjadi penanganan string di masa depan, tidak memiliki kata kunci tidak hanya tidak jujur, tetapi juga secara terang-terangan memusuhi adopsi.

/CC @MadsTorgersen @jaredpar

mengapa tidak mendapatkan kata kunci bahasa C#?

Kata kunci baru melanggar perubahan 100% setiap saat. Tidak peduli kata apa yang Anda pilih, ada perusahaan di luar sana yang memiliki jenis nama yang digunakan di mana-mana dalam proyek mereka. Satu-satunya pilihan yang kami miliki adalah kata kunci kontekstual: var misalnya.

Saya memiliki perasaan campur aduk tentang menggunakan kata kunci kontekstual untuk ini. Kata kunci tipe yang ada ( int , string , dll ...) memiliki keunggulan nyata dibandingkan nama tipe aktual ( Int32 , String ):

  • string : ini merujuk pada tipe System.String dalam rakitan yang diidentifikasi oleh kompiler sebagai corelib. Nama ini tidak memiliki ambiguitas yang terkait dengannya.
  • String : kompiler tidak memiliki pemahaman tentang jenis ini. Ini hanya tipe seperti yang lain dan melewati semua aturan pencarian yang sama seperti tipe yang Anda tetapkan. Ini mungkin setara dengan string atau mungkin tidak.

Setelah kami memperkenalkan kata kunci kontekstual di sini, maka rune dapat berupa:

  • Ketik System.Rune di dalam rakitan corelib
  • Jenis rune yang Anda definisikan dua tahun lalu ketika Anda membaca tentang Go .

Pencarian rune sama ambigunya dengan String oleh karena itu saya tidak melihat keuntungan kuat untuk menjadikannya sebagai kata kunci kontekstual.

BTW: inilah mengapa Anda harus menggunakan string dan bukan String

BTW: inilah mengapa Anda harus menggunakan string dan bukan String

Yang 99% dari alasan saya pikir orang menginginkan kata kunci bahasa. 1% lainnya hanya "terlihat lebih baik"

Jempol ke bawah untuk ketidaksukaan yang kuat dari kata kunci "rune".

Kata yang lebih baik adalah mesin terbang, karena sudah mewakili konsep umum simbol unsur dalam tipografi.

Rune adalah jenis mesin terbang tertentu yang ironisnya didefinisikan oleh Unicode. Mengacu pada Go sebagai prior art agak menggelikan. Seni sebelumnya untuk rune adalah apa yang ditulis pada tahun 150 M dan batu rune fisik yang sebenarnya. Bukan apa yang seseorang di Redmond pikirkan tentang rune. Mencoba mendefinisikan kembali konsep yang ada seperti ini tidak biasa karena .NET biasanya memiliki permukaan API yang dirancang dengan baik. Ini adalah pengecualian langka dari penamaan API yang sangat buruk dan saya ingin menyuarakan ketidakpuasan saya.

Kata yang lebih baik adalah mesin terbang, karena sudah mewakili konsep umum simbol unsur dalam tipografi.

Masalahnya adalah "Glyph" adalah istilah yang digunakan saat merender unicode ke teks yang terlihat (dari: utf8everywhere.org )

mesin terbang

Bentuk tertentu dalam font. Font adalah kumpulan mesin terbang yang dirancang oleh perancang tipe. Ini adalah tanggung jawab mesin pembentuk dan rendering teks untuk mengubah urutan titik kode menjadi urutan mesin terbang dalam font yang ditentukan. Aturan untuk konversi ini mungkin rumit, bergantung pada lokal, dan berada di luar cakupan standar Unicode.

Mengacu pada Go sebagai prior art agak menggelikan.

Menggunakan istilah Rob Pike dan Ken Thompson yang digunakan saat membuat Utf-8 https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt

Rob Pike bekerja di Go sekarang, itulah sebabnya ia menggunakan istilah aslinya.

Rune adalah jenis mesin terbang tertentu yang ironisnya didefinisikan oleh Unicode.

Runic didefinisikan oleh Unicode, Rune tidak

Runic didefinisikan oleh Unicode, Rune tidak

Saya rasa ini bukan pernyataan yang akurat, spesifikasi unicode terbaru ( http://www.unicode.org/versions/Unicode11.0.0/UnicodeStandard-11.0.pdf ) memiliki 37 klik untuk "rune" (hanya 36 yang valid , yang terakhir adalah bagian dari kata yang lebih besar) dan selalu digunakan untuk merujuk pada masing-masing huruf dari Alfabet Rahasia.

Saya tidak berpikir ini adalah pernyataan yang akurat, spesifikasi unicode terbaru memiliki 37 hit untuk "rune"

Dalam teks isi yang menjelaskan motivasi; tidak dalam nama karakter atau nama blok teks apa pun (di mana karakter Runic dan Runic-nya)

Dalam teks isi yang menjelaskan motivasi; tidak dalam nama karakter atau nama blok teks apa pun (di mana karakter Runic dan Runic-nya)

Oke, adil. Tapi kemudian kita kembali ke masalah bahwa spesifikasi Unicode saat ini tidak mendefinisikan istilah "Rune" dan ketika digunakan, itu untuk teks informatif yang menjelaskan "karakter rahasia".

Apa yang secara formal didefinisikan dan digunakan untuk menggambarkan sesuatu adalah "Titik Kode" dan "Unit Kode".

  • Bahkan jika, secara historis, pencipta asli menggunakan istilah "Rune", spesifikasi resmi tidak (dan saya akan membayangkan mereka punya alasan bagus untuk tidak menggunakannya).

Harus pendek atau penggunaannya menjadi jelek

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

Untuk panjangnya, saya benar-benar akan memilih CodePoint.IsWhiteSpace dan str.GetCodePointAt , tetapi Rune juga menyenangkan dan saya tidak keberatan.

@jnm2 Kami tidak akan menggunakan GetCodePointAt dalam hal string. Ini terlalu ambigu: kami tidak tahu apakah Anda menginginkan char yang kebetulan berada di indeks itu (karena semua char s - bahkan pengganti yang tidak berpasangan - juga merupakan poin kode yang valid) atau skalar / rune yang kebetulan berada di indeks itu.

@GrabYourPitchforks Bisakah GetRuneAt menghindari masalah yang sama, atau apakah Anda mengatakan keduanya tidak masuk akal?

@jnm2 Saya baru saja mengatakan bahwa CodePoint khususnya terlalu ambigu dalam skenario ini. Jika tidak, nama metode GetXyzAt harus cocok dengan nama tipe Xyz yang akhirnya masuk.

FYI implementasi inti sekarang diperiksa (lihat https://github.com/dotnet/coreclr/pull/20935). Berikan waktu untuk menyebar ke corefx, maka API referensi akan masuk melalui https://github.com/dotnet/corefx/pull/33395. Jangan ragu untuk membiarkan masalah ini terbuka atau menyelesaikannya sesuai keinginan Anda.

Saya tidak berharap untuk mempengaruhi siapa pun atau dapat mengubah apa pun kecuali sebagai catatan:

Kata yang lebih baik adalah mesin terbang, karena sudah mewakili konsep umum simbol unsur dalam tipografi.

Masalahnya adalah "Glyph" adalah istilah yang digunakan saat merender unicode ke teks yang terlihat (dari: utf8everywhere.org )

Garis penalaran itu juga tidak mendukung rune, karena "rune" telah menjadi istilah yang digunakan selama lebih dari seribu tahun sepanjang sejarah, jauh sebelum Unicode atau transistor atau Microsoft atau open source pernah ada. Setidaknya itu menunjukkan bahwa beberapa secara sewenang-wenang menerapkan standar yang berbeda untuk proposal yang berbeda yang jelas tidak konsisten jadi mungkin ini lebih tentang siapa yang pertama atau paling keras daripada argumen yang paling koheren, apa yang saya tahu. Saya hanya pendatang yang terlambat mencoba memahami prosesnya tetapi itu tidak masuk akal.

Mengacu pada Go sebagai prior art agak menggelikan.

Menggunakan istilah Rob Pike dan Ken Thompson yang digunakan saat membuat Utf-8 https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt

Rob Pike bekerja di Go sekarang, itulah sebabnya ia menggunakan istilah aslinya.

Go dan Rob Pike adalah pendatang baru dalam topik ini. Sebenarnya pendapat mereka agak tidak relevan dalam hal mendefinisikan apa rune secara historis dan dalam literatur populer dan masyarakat. Rob tidak memalu batu rune sendiri dengan tangan sehingga dia memiliki sedikit kualifikasi untuk mendefinisikan apa itu rune. Aku yakin dia bahkan tidak bisa menulis atau membaca skrip rune sendiri tapi itu tebakanku. Paling-paling dia bisa menangkap konsep itu melalui pengkodean, tapi dia tidak bisa masuk dan mengatakan bahwa karakter Cina, tulisan Arab atau Hangul atau wajah tersenyum adalah rune atau apa pun yang merupakan "Code Point" sekarang juga Rune, atau semacam itu. Tampaknya hampir tidak sopan menginjak-injak istilah, lihat, sekarang semuanya bisa menjadi rune, yang berarti, rune tidak lain adalah istilah wildcard empat huruf untuk merujuk pada sesuatu yang esoterik dalam domain teks penyandian.

Rune adalah jenis mesin terbang tertentu yang ironisnya didefinisikan oleh Unicode.

Runic didefinisikan oleh Unicode, Rune tidak

Unicode tidak seharusnya mendefinisikan ulang apa itu rune atau runic. Jika mereka melakukan itu, mereka melanggar mandat mereka. Mereka tidak punya urusan memberi tahu publik apa itu rune. Sebenarnya mereka tidak punya urusan untuk mendefinisikan bahasa atau sistem karakter baru apa pun. Mereka tidak bisa begitu saja mengambil kata yang sudah menjadi istilah yang jelas-jelas kelebihan beban sejak seribu tahun lalu dan kemudian berlarian bersorak seolah mereka telah menemukan konsep baru. Penulisan rahasia hanya terdiri dari rune, dan rune sudah menjadi konsep yang mapan. Jika Anda bertanya kepada orang acak di jalan apa itu rune, mereka tidak akan memikirkan Unicode.

Selain semua masalah di atas, rune adalah metafora yang buruk yang merupakan bagian terburuk. Itu tidak menjelaskan apa pun. Itu hanya menambah tingkat kebingungan. Setiap pendatang baru pada topik sekarang perlu melalui penjelasan dan pembacaan disambiguasi karena semua orang masuk dengan konteks bahwa rune adalah sistem penulisan sejarah yang digunakan dalam budaya tertentu. Penjelasannya harus seperti ini: "Rune adalah titik kode Unicode". "Tapi mengapa tidak menyebutnya titik kode?" "Yah, karena terlalu panjang.", Atau "Seseorang memutuskan bahwa mereka menyukai rune". Jadi pada dasarnya, karena seseorang menganggap 9 huruf terlalu banyak dibandingkan dengan 4 (walaupun mereka memiliki kelengkapan otomatis dengan Intellisense dan tidak ada apa-apanya dibandingkan dengan Java Kingdom Of Nouns), sekarang kita harus mengatasi kebingungan ini dan menjelaskannya kepada ribuan pengembang yang mungkin perlu mencoba-coba Unicode. Cukup gunakan pernyataan using untuk mempersingkat istilah jika Anda sering menggunakannya dalam kode.

Tidak harus UnicodeCodePoint juga, cukup CodePoint. Ini sudah unik. Ada banyak istilah API yang lebih panjang dari "CodePoint" sehingga sudah cukup. Jika masih terlalu panjang, sebaiknya gunakan pernyataan using dengan beberapa singkatan.

Saya memperkirakan ini menjadi salah satu pertanyaan wawancara gotcha yang benar-benar tidak menambah banyak nilai atau memiliki dasar logis dalam sesuatu yang bermanfaat. Setidaknya untuk metafora "tonggak", sementara kita berada pada topik kata-kata simbolis yang digunakan dalam pengembangan perangkat lunak berdasarkan konsep yang berasal dari batu dan batu, tonggak memiliki arti deskriptif yang nyata. Ini segera mengomunikasikan konsep yang dikenal semua orang. Aha, tonggak sejarah, seperti ketika Anda dalam perjalanan panjang dan Anda lewat di jalan setapak. Ini adalah metafora dunia nyata yang bagus yang benar-benar membantu untuk memvisualisasikan sesuatu dan dapat menjadi bahasa manajerial secara instan. Saya tidak bisa membayangkan orang berbicara tentang rune dengan cara ini kecuali mereka sangat akrab dengan topik tersebut, di mana mereka sudah akan tahu bahwa itu hanya istilah gimmick untuk titik kode.

Kata yang lebih baik adalah mesin terbang, karena sudah mewakili konsep umum simbol unsur dalam tipografi.

Masalahnya adalah "Glyph" adalah istilah yang digunakan saat merender unicode ke teks yang terlihat (dari: utf8everywhere.org)

Garis penalaran itu juga tidak mendukung rune, karena "rune" telah menjadi istilah yang digunakan selama lebih dari seribu tahun sepanjang sejarah, jauh sebelum Unicode atau transistor atau Microsoft atau open source pernah ada.

Maksud saya adalah kata "glyph" bermasalah karena sudah digunakan sebagai salah satu konsep dalam rendering teks; ini adalah representasi grafis dari karakter itu dalam font tertentu. Jadi karakter dapat diwakili oleh banyak mesin terbang yang berbeda.

... lagi dengan @benaadams memiliki pandangan 10.000 meter dan jawaban yang benar 😁

Sejujurnya, kita harus hidup dengan pepatah lama: "Anda dapat membuat beberapa orang bahagia sepanjang waktu, dan semua orang bahagia di beberapa waktu; tetapi Anda tidak dapat membuat semua orang bahagia sepanjang waktu. waktu." Ini sangat banyak situasi mantan.

Sigil?

Exit, pursued by a bear.

Sebagai seseorang yang akan menggunakan API ini secara ekstensif, saya memberikan suara yang kuat untuk poin kode. Terminologi Unicode sudah cukup membingungkan, dan inkonsistensi sudah berlimpah. Anda akan membuat hidup saya jauh lebih mudah jika saya bisa mengatakan "titik kode" di mana-mana.

Aku sedang berbaring di tempat tidur sekarang. Jika saya berbelok ke samping, saya menghadapi papan tulis yang disandarkan ke dinding saya. Selama berbulan-bulan, papan tulis itu telah menjadi rumah bagi berbagai coretan dan bagan sementara saya mencoba mencari cara untuk menangani IDN secara efisien di C#. Saya memperlakukannya seperti peninggalan yang saya panggil dari kedalaman neraka. Jika saya mencoba menjelaskan logika yang dijelaskannya, saya tidak akan bisa.

Tolong, jangan buat hidupku semakin sulit. Titik kode adalah titik kode. Ini bukan rune, glyph, karakter, grafem, atau bahkan simbol. Itu tidak perlu mewakili sesuatu yang berarti bagi manusia — itu bisa menjadi kode kontrol. Ini mungkin tidak mewakili simbol visual, seperti yang tersirat dari nama "rune". Itu hanya poin kode.

Argumen yang lebih konkret adalah bahwa "rune" menyiratkan representasi dari grafem tunggal, yang seringkali tidak demikian. Jika saya menghitung jumlah poin kode dan jumlah grafem, saya mungkin mendapatkan dua angka yang sangat berbeda. Urutan grafem yang sama dapat diwakili oleh dua seri titik kode yang berbeda.

Kata yang lebih baik adalah mesin terbang, karena sudah mewakili konsep umum simbol unsur dalam tipografi.

Itu bahkan lebih buruk. Satu titik kode dapat diwakili oleh beberapa mesin terbang, dan satu mesin terbang dapat mewakili beberapa titik kode. Pemetaan yang tepat dapat bervariasi menurut sistem, program, jenis huruf...

Semua kata ini memiliki arti teknis yang sangat spesifik. Meskipun perbedaannya mungkin tampak tidak signifikan dalam konteks proposal ini, perbedaan tersebut memiliki konsekuensi nyata di tempat lain, terutama dalam bahasa selain bahasa Inggris.

Sebagai contoh betapa sulitnya menangani teks, bahkan dalam bahasa yang umum seperti bahasa Jerman:

  1. Ubah ß menjadi huruf besar dan Anda akan mendapatkan SS .
  2. Ubah kembali menjadi huruf kecil dan Anda akan mendapatkan ss .

Masalah:

  • Apa yang harus dikembalikan char.ToUpper('ß') ? (Itu harus mengembalikan satu karakter.)
  • Versi kapital dari yang tidak dapat dimasukkan oleh ponsel saya ke dalam kotak teks ini telah ditambahkan ke Unicode 5.1. Jika saya mencoba menempelkannya, saya mendapatkan SS. Sekarang konversi atas/bawah bahkan lebih ambigu.
  • Mengubah casing string mengubah panjangnya.
  • Perubahan kasus tidak idempoten atau reversibel.
  • Anda tidak dapat melakukan perbandingan case-insensitive hanya dengan menurunkan setiap string.

Meskipun ini bukan contoh langsung dari situasi di mana terminologi menyebabkan masalah, ini menunjukkan bagaimana ada jenis kasus tepi yang biasanya tidak kita pikirkan. Memberi setiap istilah makna yang berbeda dan konsisten membantu programmer mengomunikasikan masalah ini. Jika saya meminta rekan satu tim untuk menulis fungsi untuk menghitung grafem, mereka tahu persis apa yang akan mereka hitung dan bagaimana melakukannya. Jika saya meminta mereka untuk menghitung poin kode, sekali lagi, mereka tahu persis apa yang harus dilakukan. Definisi ini tidak bergantung pada bahasa dan teknologi yang kami gunakan.

Jika saya meminta pengembang JavaScript untuk menghitung rune, mereka akan melihat saya seperti saya memiliki tiga kepala.

Wikipedia mengatakan

Unicode mendefinisikan ruang kode dari 1.114.112 poin kode dalam kisaran 0hex hingga 10FFFFhex

Titik kode tampaknya menjadi nama resmi. Saya telah membaca utas ini dan belum menemukan argumen yang memaksa mengapa titik kode salah.

Saya setuju bahwa titik kode bukanlah istilah yang tepat untuk digunakan di sini. Paling tidak, berdasarkan standar Unicode tidak termasuk nilai di atas 10FFFF (http://unicode.org/glossary/#code_point).

Mungkin kalimat itu salah? Dikatakan "nilai apa pun dalam ruang kode". Jadi itu jelas berarti segalanya sementara pada saat yang sama mendapatkan bilangan bulat yang salah.

Juga, "rune" memiliki arti dunia nyata yang tidak ada hubungannya dengan Unicode. Di Jerman, kata "Rune" memiliki konotasi Nazi karena rune memiliki sejarah "Jerman" yang disukai oleh Nazi.

Saya menemukan "rune" menjadi nama yang membingungkan. Apakah ada orang di sini yang benar-benar menyukai "rune" atau apakah argumennya didasarkan pada kebenaran. Secara intuitif, itu adalah nama yang sangat buruk.

Mungkin kalimat itu salah? Dikatakan "nilai apa pun dalam ruang kode". Jadi itu jelas berarti segalanya sementara pada saat yang sama mendapatkan bilangan bulat yang salah.

Kalimat itu benar. Ruang kode adalah dari U+0000 hingga U+10FFFF. Unicode secara teoritis dapat diperluas lebih dari itu suatu hari nanti, tetapi itu akan merusak UTF-8 dan UTF-16. Kami membutuhkan penyandian baru.

Sunting: Sebenarnya, jangan mengutip saya tentang kerusakan UTF-16, tapi saya cukup yakin itu akan merusak UTF-8. UTF-8 pasti tidak dapat mewakili 0xFFFFFF (2^24 -1).

Sunting 2: Untuk memperjelas, Unicode menyatakan bahwa poin kode tidak dapat melebihi U+10FFFF. Itu tidak berarti saat ini ada 0x110000 poin kode--sebagian besar poin kode tersebut belum ditetapkan.

@Zenexer @GSPP

Jenis ini seperti yang saat ini diperiksa ke master ( System.Text.Rune ) memetakan secara khusus ke "nilai skalar Unicode" ( lihat glosarium ). Ktor tipe akan mengeluarkan pengecualian jika Anda mencoba membangunnya dari nilai -1 , 0xD800 , atau 0x110000 , karena ini bukan nilai skalar per spesifikasi Unicode. Jika Anda menggunakan parameter Rune sebagai input ke metode Anda, Anda tidak perlu melakukan pemeriksaan validasi apa pun. Sistem tipe telah memastikan bahwa itu dibangun dari nilai skalar yang valid.

Re: konversi kasus, semua API konversi kasus di .NET Framework _kecuali dinyatakan lain_ menggunakan teknik yang disebut pelipatan kasus sederhana. Di bawah aturan untuk pelipatan huruf sederhana, untuk nilai skalar input apa pun, bentuk huruf kecil, huruf besar, dan huruf besar keluaran juga masing-masing dijamin tepat satu nilai skalar. (Beberapa input, seperti angka 0-9 atau simbol tanda baca, tidak memiliki entri dalam peta konversi kasus. Dalam kasus ini, operasi seperti _ToUpper_ hanya mengembalikan nilai skalar input.) Selain itu, di bawah aturan pelipatan huruf sederhana jika inputnya adalah di Basic Multilingual Plane (BMP), maka outputnya juga harus dalam BMP; dan jika input berada di bidang tambahan, output juga harus berada di bidang tambahan.

Ada beberapa konsekuensi untuk ini. Pertama, Rune.ToUpper dan teman-teman akan selalu mengembalikan nilai _Rune_ (skalar) tunggal. Kedua, String.ToUpper dan teman-teman akan selalu mengembalikan string dengan panjang yang sama persis dengan inputnya. Ini berarti bahwa string yang mengandung 'ß' (miniscule eszett), setelah operasi konversi kasus, mungkin berakhir berisi 'ß' (tidak ada perubahan) atau 'ẞ' (majuscule eszett), tergantung pada budaya yang digunakan. Tapi _tidak__ mengandung "SS", karena ini akan mengubah panjang string, dan hampir semua API konversi kasus .NET yang diekspos ke publik menggunakan aturan pelipatan huruf kecil sederhana. Ketiga, Utf8String.ToUpper dan teman-teman (belum check-in) _tidak_ dijamin mengembalikan nilai yang properti _Length_-nya cocok dengan properti _Length_ nilai input. (Jumlah unit kode UTF-16 dalam string tidak dapat berubah setelah pelipatan huruf sederhana, tetapi jumlah unit kode UTF-8 dalam string dapat berubah. Hal ini disebabkan bagaimana nilai BMP dikodekan oleh UTF-16 dan UTF- 8.)

Ada beberapa .NET API yang secara internal menggunakan aturan pelipatan huruf yang rumit daripada aturan pelipatan huruf yang sederhana. String.Equals , String.IndexOf , String.Contains , dan operasi serupa menggunakan aturan pelipatan huruf besar-kecil yang rumit di bawah penutup, bergantung pada budaya. Jadi, jika budaya Anda disetel ke _de-DE_, string satu karakter "ß" dan string dua karakter "SS" akan dibandingkan sebagai sama jika Anda meneruskan _CurrentCultureIgnoreCase_.

@GrabYourPitchforks Saya terutama keberatan dengan pilihan nama. Contoh casefolding murni untuk menekankan betapa rumitnya Unicode (dan teks secara umum). Selama ada beberapa cara untuk menangani normalization , saya tidak terlalu peduli bagaimana operasi sederhana bekerja, karena saya akan tetap mengonversi ke NFKD untuk semuanya untuk kasus penggunaan saya.

Kalimat itu benar. Ruang kode adalah dari U+0000 hingga U+10FFFF. Unicode secara teoritis dapat diperluas lebih dari itu suatu hari nanti, tetapi itu akan merusak UTF-8 dan UTF-16. Kami membutuhkan penyandian baru.

Hanya untuk nitpicking (atau, jika orang tertarik): Secara teori, algoritma UTF-8 bekerja hingga 42 bit (Awalan Byte 0xFF dan 7 byte dari 6 bit payload), dan awalnya, spesifikasi pertama mencakup keseluruhan 31 bit space dari Universal Character Set (UCS4) versi lama - namun, spesifikasi saat ini (RFC 3629, Unicode Standard, Annex D dari ISO/IEC 10646) semuanya setuju untuk membatasinya pada rentang codepoint yang valid saat ini (U+ 0000 hingga U+10FFFF).

Untuk UTF-16, situasinya lebih sulit. Tetapi mereka dapat memesan poin kode di bidang atas sebagai "Escapes" untuk 32 bit atau lebih. Karena Pesawat 3 hingga 13 saat ini tidak ditentukan, mereka dapat memesan dua di antaranya sebagai "pesawat pengganti rendah" dan "pesawat pengganti tinggi". Kemudian titik kode 32 bit akan dipecah menjadi dua nilai 16 bit (satu di setiap bidang), dan kemudian setiap nilai akan dikodekan menggunakan dua pengganti "klasik", secara efektif menggunakan 4 unit kode masing-masing 16 bit untuk mengkodekan titik kode 32 bit.

Btw, AFAICS, konsorsium unicode secara terbuka menyatakan bahwa mereka tidak akan pernah mengalokasikan codepoint di atas U+10FFFF, jadi dalam praktiknya, saya harap saya akan lama pensiun sebelum itu benar-benar terjadi. :mengedip:

Jenis ini seperti yang saat ini diperiksa ke master ( System.Text.Rune ) memetakan secara khusus ke "nilai skalar Unicode"

@GrabYourPitchforks terima kasih atas klarifikasinya. Ini berarti bahwa struct tidak mewakili titik kode. Jadi nama itu memang akan salah.

Saya kira UnicodeScalar terlalu misterius sebagai sebuah nama...

@GrabYourPitchforks , apa yang tersisa untuk dilakukan untuk masalah ini?

@stephentoub Tidak ada fungsionalitas tambahan yang direncanakan untuk tipe Rune in-box untuk 3.0, tetapi @migueldeicaza punya ide untuk memperluas jangkauan tipe, termasuk untuk hal-hal seperti cluster grapheme. (Hal terdekat yang kami miliki di kotak adalah TextElementEnumerator , yang merupakan tipe yang sangat ketinggalan zaman.) Beberapa dari ide-ide itu dibahas di utas ini tetapi belum ada yang konkret.

Kami dapat membiarkan masalah ini terbuka jika komunitas ingin mendiskusikan skenario lebih lanjut, atau kami dapat mengarahkan orang-orang untuk membuka masalah baru jika mereka ingin memberikan saran khusus. TBH Saya tidak memiliki preferensi yang kuat.

Terima kasih. Karena Rune sudah diperkenalkan dan API yang diuraikan di sini (atau perkiraannya) sudah diekspos, mari kita tutup ini. Dukungan tambahan dapat diatasi melalui masalah terpisah.

Jadi, apakah ini pada dasarnya stabil pada titik ini? Karena sejujurnya nama mengerikan ini, yang tidak sejalan dengan informasi apa pun yang akan Anda temukan tentang Unicode dari sumber yang baik dan akurat, dan memiliki nuansa yang tidak menguntungkan untuk menyiratkan mesin terbang yang bertentangan dengan karakter noncetak, hanya akan memperburuk pemahaman Unicode yang sudah mengerikan oleh programmer rata-rata Anda.

Saya tahu ini telah diintegrasikan pada titik ini, tetapi saya hanya ingin membahas bagian Rune dan beberapa orang tidak setuju tentang nama tersebut.

Saya pertama kali menemukan Rune di Paket 9, dan seperti orang lain telah melihatnya di Go dan lainnya. Ketika msdocs mulai mendaftar Rune Saya tahu persis apa itu sebelum membaca.

Setidaknya dalam dua contoh, Plan 9 dan Go, Anda memiliki individu yang bertanggung jawab atas UTF-8 menggunakan nama Rune . Saya pikir aman untuk mengatakan bahwa mereka sudah memikirkan masalah ini dan masih menganggap Rune masuk akal. Runic sebenarnya bukan sistem penulisan yang digunakan lagi, selain dengan beberapa tradisionalis. Dan Rune memang berarti grafem dalam sistem itu, sama seperti yang pada dasarnya berarti grafem di sini (kecuali dalam kasus seperti karakter kontrol.

Saya benar-benar melihat sedikit yang salah dengan penamaan. Runic adalah sistem penulisan yang sangat tua, saya sangat ragu programmer rata-rata Anda akan membingungkannya, dan sudah ada standar de-facto yang berumur beberapa dekade Rune untuk "karakter" Unicode yang tepat.

@Entomi

sama seperti itu pada dasarnya berarti grafem di sini (kecuali dalam kasus seperti karakter kontrol.

Ini tidak benar. Unicode berisi sejumlah besar poin kode yang telah disusun sebelumnya yang mewakili beberapa grafem (umumnya kombinasi huruf dan diakritik), dan ini biasanya digunakan untuk menulis bahasa seperti Prancis dan Spanyol, dan hampir semua teks komputerisasi dalam bahasa ini akan menggunakan kode tersebut poin.

Sebaliknya, bahkan ketika satu titik kode mewakili satu grafem, sangat umum bagi mereka untuk bergabung menjadi _kelompok grafem_, yang penting untuk penanganan teks yang tepat di sebagian besar bahasa India. Jadi, satu karakter seperti yang dirasakan oleh pengguna saat bergerak dengan tombol panah sering kali sesuai dengan beberapa titik kode secara berurutan. Jadi, tidak ada korespondensi yang mudah dibuat antara titik kode dan baik grafem atau cluster grafem. Bahkan "karakter" mungkin akan menjadi nama yang lebih baik, mengingat programmer terbiasa menganggap karakter aneh dan aneh pada saat ini, sementara "rune" memberi kesan bahwa masalah mencari tahu batas karakter yang dirasakan pengguna telah dipecahkan untuk programmer sudah padahal sebenarnya belum.

Ketika msdocs mulai mendaftar Rune, saya tahu persis apa itu sebelum membaca.

Fakta bahwa Anda berpikir bahwa nama rune menggambarkan grafem dengan baik adalah bukti yang sangat baik dari masalah yang saya miliki di sini: nama "rune" memberi programmer rasa aman yang salah dengan membuatnya lebih mudah untuk mengasumsikan bahwa ada korespondensi seperti itu.

Setidaknya dalam dua contoh, Paket 9 dan Mulai, Anda memiliki individu yang bertanggung jawab atas UTF-8 menggunakan nama Rune .

Sama seperti saya menghormati Ken Thompson dan Rob Pike, pekerjaan mereka di sini pada dasarnya hanya merancang skema yang sangat cerdas untuk mengkodekan serangkaian bilangan bulat dengan panjang variabel. Mereka bukan ahli Unicode secara keseluruhan, dan saya sangat tidak setuju dengan mereka tentang masalah ini. Saya akui bahwa saya juga bukan ahli Unicode, tetapi menurut saya daya tarik otoritas di sini tidak sekuat kelihatannya.

dan sudah ada standar de-facto Rune yang berumur beberapa dekade untuk "karakter" Unicode yang tepat.

"Standar" katamu? Sebagian besar hanya dua ini yang mendorong nama, dan beberapa bahasa pemrograman kecil seperti Nim mengadopsinya dari Go. Dan tentu saja saya harus ulangi lagi bahwa titik kode tidak mewakili satu “karakter Unicode yang tepat” baik itu dalam arti pemilihan, gerakan tombol panah, grafem, atau klaster grafem.

...pada dasarnya berarti grafem di sini...

Ya, karena tidak persis tapi kira-kira cukup dekat. Grafem, setidaknya seperti yang didefinisikan dalam linguistik, adalah komponen ortografis yang membentuk sistem penulisan dan digunakan untuk mengekspresikan fonem. Ini bukan hal 1:1. Dalam suku kata dan suku kata logo, satu grafem dapat mewakili banyak fonem, biasanya pasangan konsonan-vokal. Sebaliknya, menurut abjad bahasa sering memiliki kasus beberapa grafem yang mewakili satu fonem, seperti "th" dalam bahasa Inggris yang bertanggung jawab untuk et dan duri kuno, tergantung pada kata tertentu. Kemudian Anda bahkan tidak dapat menemukan kesepakatan lintas bahasa, apakah huruf seperti 'á' adalah huruf uniknya sendiri, atau 'a' dengan aksen. Kami bahkan tidak dapat membangun konsistensi dalam bahasa yang berusia lebih dari ribuan tahun. Kami tidak akan memiliki tambahan yang sangat konsisten di atas itu, yaitu pengkodean ini.

Karena Anda memperdebatkan semantik yang sangat ketat, apa yang disebut UNICODE sebagai "klaster grafem" sering kali dalam linguistik hanya satu grafem. Apakah UNICODE ini tidak valid? Tidak. Apakah ini berarti UNICODE perlu mengganti namanya? Tidak Memangnya kenapa? Karena konteks. Bidang memiliki istilahnya sendiri, dan selama tidak ada penggabungan dalam satu bidang, itu tidak menjadi masalah.

Saya tidak melihat nama sebagai masalah yang terlalu besar. Msdocs jelas tentang apa Rune dalam ringkasan. Jika orang tidak membaca dokumen itu masalah mereka sendiri. Orang-orang tidak bereaksi keras terhadap 'Aliran' dan mengatakan omong kosong seperti "oh tapi bagaimana jika orang mengira itu sungai kecil, karena itu sudah memiliki nama yang sama!" Tidak.

@Serentty @Entomy Anda berdua mungkin juga tertarik dengan kelas StringInfo , yang memperlihatkan konsep Unicode yang sebenarnya "klaster grapheme yang diperluas". Jenis StringInfo cukup kuno dan sebagai hasilnya menerapkan versi standar Unicode yang sangat lama, tetapi ada pekerjaan aktif untuk memperbaruinya agar sesuai dengan UAX #29, Sec.

Ya, karena tidak persis tapi kira-kira cukup dekat.

Saya pikir masalah representasi yang tersusun versus yang terurai membuat ini tidak benar. Jika kita menggunakan definisi linguistik grafem di sini sebagai lawan dari definisi terkait komputasi apa pun, maka dan adalah urutan grafem yang sama persis (tiga Hangul jamo mewakili suku kata _han_ sebagai segmen HAN), dan namun yang pertama hanya satu titik kode sedangkan yang kedua adalah urutan tiga.

Bidang memiliki istilahnya sendiri, dan selama tidak ada penggabungan dalam satu bidang, itu tidak menjadi masalah.

Ini persis poin saya juga. Unicode adalah sistem yang sangat rumit dengan terminologinya sendiri, jadi mengapa mencoba memaksakan semacam istilah "intuitif" setengah matang ke dalamnya ketika tidak berbaris secara akurat? Poin kode adalah poin kode. Mereka tidak memiliki paralel linguistik, dan mencoba untuk menjadi intuitif sementara hanya 75% akurat adalah resep untuk jenis bencana yang sama yang C# masih mencoba untuk pulih dari.

Karena Anda memperdebatkan semantik yang sangat ketat, apa yang disebut UNICODE sebagai "klaster grafem" sering kali dalam linguistik hanya satu grafem.

Dalam standar, sebuah cluster diizinkan untuk hanya terdiri dari satu grafem. Tidak ada yang salah dengan ini di sini. _cluster_ adalah unit pemilihan teks dan pergerakan kursor.

Saya tidak melihat nama sebagai masalah yang terlalu besar. Msdocs jelas tentang apa Rune dalam ringkasan. Jika orang tidak membaca dokumen itu masalah mereka sendiri.

Ini adalah argumen "pemrogram harus lebih pintar" yang muncul berulang kali untuk membela keputusan desain yang buruk. Jika programmer perlu membaca dokumentasi dan mempelajari bahwa rune adalah titik kode Unicode, lalu apa gunanya menyebutnya sebagai nama yang lebih "intuitif"? Argumen di sini tampaknya adalah bahwa "titik kode" membingungkan, jadi masuk akal untuk memilih nama yang lebih intuitif, tetapi kemudian ketika menghadapi masalah nama yang menyesatkan, pembelaannya adalah bahwa programmer harus tahu apa itu titik kode. dari membaca dokumentasi. Jika itu masalahnya, mengapa tidak memanggil tipe CodePoint dan mempermudah programmer untuk mencari dan mempelajarinya? Ini semua mengesampingkan masalah bahwa dokumentasi .NET cukup mengerikan berkaitan dengan Unicode di tempat pertama, memperlakukan pasangan pengganti sebagai renungan di dunia "karakter Unicode 16-bit".

Ini adalah argumen "pemrogram harus lebih pintar" yang muncul berulang kali untuk membela keputusan desain yang buruk.

Saya tidak pernah mengatakan ini.

Argumen di sini tampaknya "titik kode" membingungkan

Saya juga tidak pernah mengatakan ini.

Orang-orang tidak bereaksi keras terhadap 'Aliran' dan mengatakan omong kosong seperti "oh tapi bagaimana jika orang mengira itu sungai kecil, karena itu sudah memiliki nama yang sama!" Tidak.

Saya mengatakan bahwa programmer cukup pintar untuk tidak berpikir Rune secara khusus rune rune, sama seperti mereka tahu Stream bukan sungai kecil.

Biarkan saya ulangi ini

Saya mengatakan programmer cukup pintar untuk mengetahui hal ini. Anda memasukkan kata-kata ke dalam mulut saya.

Saya tidak melihat nama sebagai masalah yang terlalu besar. Msdocs jelas tentang apa Rune dalam ringkasan. Jika orang tidak membaca dokumen itu masalah mereka sendiri.

Inilah yang saya maksud di sini. Argumen yang mendukung nama "rune" didasarkan pada intuisi dan koneksi intuitif dengan gagasan grafem. Anda sendiri berdebat bahwa keduanya berbaris cukup dekat sehingga itu tidak menjadi masalah. Ketika saya menunjukkan semua cara bahwa intuisi itu salah dan korespondensinya bisa sangat buruk, tanggapan Anda pada dasarnya adalah bahwa itu tidak masalah karena programmer tetap perlu membaca dokumentasi. Inilah yang saya maksud dengan “programmer harus lebih pintar.” Dokumentasi bukanlah alasan untuk menyesatkan nama ketika tidak ada alasan warisan untuk mereka.

Saya mengatakan bahwa programmer cukup pintar untuk tidak berpikir Rune secara khusus rune rune, sama seperti mereka tahu Stream bukan sungai kecil.

Argumen saya di sini bukanlah bahwa orang akan bingung dengan rune rune. Argumen saya adalah bahwa orang akan mengacaukannya dengan glif, grafem, dan klaster grafem, yang terlepas dari desakan Anda semua berkorelasi sangat buruk dengan poin kode.

Saya mengatakan programmer cukup pintar untuk mengetahui hal ini. Anda memasukkan kata-kata ke dalam mulut saya.

Cukup pintar untuk mengetahui bahwa itu bukan rune Jermanik yang sebenarnya, tentu saja. Tetapi untuk mengetahui bahwa itu bukan mesin terbang, grafem, atau kelompok grafem? Pengalaman saya yang sebenarnya dengan kualitas penanganan sebagian besar perangkat lunak Unicode mengatakan tidak.

Jika orang tidak membaca dokumen itu masalah mereka sendiri.

Ya, dan saya mendukung ini. Bukan karena kekurangan kecerdasan, melainkan kecenderungan ke arah asumsi yang tergesa-gesa.

Jika seorang programmer menganggap String berarti seutas tali yang kuat, tipis, terbuat dari pelintiran benang, karena ya memang begitu, itu tidak dianggap masalah dengan nama String .

Jika seorang programmer menganggap Char berarti bahan yang hangus seperti arang, atau jenis ikan trout tertentu, itu tidak dianggap masalah dengan nama Char .

Jika seorang programmer menganggap character berarti penggambaran serangkaian sifat mental dan etika yang digunakan dalam mendongeng, itu tidak dianggap masalah dengan nama character .

Perhatikan ini semua adalah masalah teks/linguistik. Mereka semua memiliki arti lain. Namun programmer telah menyesuaikan diri dengan baik. Istilah-istilah itu telah menjadi standar de facto, karena konvensi yang mapan di lapangan: istilah kita. Ada preseden mapan bahwa programmer _are_ cukup pintar untuk mengikuti ini.

Anda sendiri berdebat bahwa keduanya berbaris cukup dekat sehingga itu tidak menjadi masalah.

Ya ini GitHub. Pada masalah yang sudah ditutup, di mana saya baru saja menambahkan pemikiran saya tentang mengapa saya merasa Rune baik-baik saja karena ada beberapa preseden yang mapan dalam nama tersebut. Ini bukan tempat atau konteks untuk menulis risalah, penuh dengan definisi yang luas dan kata-kata yang dipilih dengan cermat. Misalnya, jika saya memasukkan PR untuk, katakanlah, dekoder UTF-8, saya tidak akan menjelaskan secara eksplisit mengapa saya menerapkan DFA Hoehrmann daripada pendekatan alternatif. Saya hanya akan mengatakan "ini dia, ini beberapa buktinya, ini beberapa tolok ukur yang mendukung mengapa saya menggunakan ini".

Argumen saya adalah bahwa orang akan mengacaukannya dengan glif, grafem, dan klaster grafem

Mereka tidak membingungkan salah satu dari yang disebutkan di atas, atau Tree , Heap , Table , Key , Socket , Port ...

Ini adalah argumen yang sangat tidak jujur. Sepotong utas dan untaian teks tidak mudah dikacaukan. Struktur data tanaman tinggi dan pohon tidak mudah membingungkan. Sebuah titik kode di sisi lain adalah konsep yang sangat kurang dipahami oleh sebagian besar programmer, dan terus-menerus bingung dengan semua konsep lain yang telah kita diskusikan. Solusi untuk ini adalah, seperti yang Anda katakan, membaca dokumentasi. Namun, bahasa yang menggunakan nama "pintar" sendiri untuk poin kode membuatnya semakin sulit untuk menerapkan pengetahuan dari _dokumentasi Unicode aktual_ ke bahasa itu. Dan itu membawa saya ke ini:

Istilah-istilah itu telah menjadi standar de facto, karena konvensi yang mapan di lapangan: istilah kita.

Dan inilah inti dari semuanya. Anda tampaknya mengklaim bahwa "rune" adalah istilah yang sudah mapan untuk titik kode yang dipahami secara luas dalam pemrograman, atau memang seharusnya begitu. Jika itu yang pertama, maka saya mengundang Anda untuk bertanya kepada seorang programmer rata-rata yang berpengalaman dalam bahasa pemrograman utama selain Go apakah mereka pernah mendengarnya. Jika itu yang terakhir, maka saya akan menanyakan maksud Anda bersaing dengan terminologi Unicode resmi dalam situasi yang sudah membingungkan dan kurang dipahami yang sering disalahpahami oleh pengembang yang bahkan sangat berpengalaman.

Masukan orang luar @Entomy : seluruh argumen Anda, sejauh yang saya tahu, adalah 'membingungkan dan buruk, ya, tetapi tidak terlalu membingungkan dan buruk'.
Jadi? Mengapa tidak bisa benar-benar bagus? Apa masalah dengan menamainya persis apa yang Unicode beri nama itu?
Juga, rune bukanlah titik kode, atau bahkan grafem atau cluster, dalam bidang komputasi umum. Jika Anda mencari 'rune Unicode' di Google, apa pun yang berhubungan dengannya dengan poin kode tidak akan muncul hingga halaman 2, dan itu pun hanya tautan godoc / Nim. Bahkan di DuckDuckGo, yang programmer mungkin lebih nyaman, itu masih hasil halaman 2. Jadi satu-satunya argumen yang tersisa untuk nama yang saya lihat adalah bahwa itu intuitif bahwa itu mewakili titik kode, tetapi bukan . Ini intuitif bahwa itu mewakili cluster grafem, atau mungkin hanya grafem.
Sumber: Saya telah menggunakan Go dan saya pikir itu adalah grafem sampai empat tahun kemudian ketika saya membaca edisi ini sekarang.

(dan mengatakan bahwa boleh saja itu menyarankan grafem karena 'cukup dekat' mengingatkan saya pada karakter 16-bit yang cukup dekat.)
Ya, jika pemrogram lebih pintar dan membaca lebih banyak dokumentasi, kami tidak memerlukan nama yang bermakna untuk itu, atau bahkan tipe sama sekali. Orang hanya akan tahu untuk melewatkan poin kode di int alih-alih char. Tapi tidak. Mereka secerdas mereka sekarang, dan itu tidak akan berubah hanya karena Yet Another API telah ditambahkan. Tujuannya adalah untuk meningkatkan jumlah perangkat lunak yang menangani bahasa selain bahasa Inggris dengan benar, tidak hanya memperkenalkan cara-cara baru untuk melakukan hal yang sama dan mempertahankan hambatan masuk yang sama seperti sebelumnya.

Hanya demi argumen, dan untuk tujuan ilmiah, saya ingin menunjukkan kepada semua orang di sini pada satu bahasa pemrograman yang paling baik menangani teks Unicode, di mana »terbaik« didefinisikan oleh »paling dekat sesuai dengan standar Unicode«, bukan dengan memalsukan kesederhanaan: Swift

  • String adalah buffer teks Unicode arbitrer.
  • Character , yang Anda ulangi dan yang tidak, bukanlah Nilai Skalar Unicode tunggal, tetapi Cluster Grapheme yang Diperluas. Lihat contoh ini untuk cluster grafem : let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
  • Jika Anda membutuhkan Nilai Skalar Unicode, Anda juga dapat mengulanginya. Tipe mereka disebut UnicodeScalar .
  • Dan jika Anda benar-benar merasa membutuhkannya, Anda juga dapat mengulangi unit kode UTF-8 dan UTF-16, menghasilkan UInt 8 s dan UInt 16 s.

Sekarang, saya di sini tidak menyarankan agar C# menggunakan gaya Swift penuh. Meskipun ini akan luar biasa, ini juga membutuhkan banyak perubahan dan pekerjaan. Saya di sini untuk menyarankan mengambil penamaan gaya Swift, bagaimanapun, untuk semua alasan yang ditunjukkan @Serentty , dan membiarkan opsi terbuka untuk mengubah string teks gaya Swift pada akhirnya.

Beberapa nama potensial yang lebih baik daripada Rune : CodeUnit32 , UnicodeScalar , CodeUnit , UniScalar , UnicodeValue , UniValue , UnicodeScalarValue . Saya pikir dua yang pertama mungkin cocok dengan konvensi penamaan C#. Perhatikan bahwa UnicodeScalar secara objektif adalah nama yang lebih baik, karena unit kode hanyalah cara untuk menyandikan Nilai Skalar Unicode dalam istilah Unicode. Jadi CodeUnit32 menyiratkan iterasi atas unit kode dari string teks yang disandikan UTF-32, sedangkan UnicodeScalar adalah pengkodean-agnostik.

Sunting: Ya, nama System.Rune sudah ada di luar sana. Semua ini hanyalah sebuah »jika kita ingin membuatnya lebih baik sebelum benda ini berumur setengah dekade«.

@pie-flavor

seluruh argumen Anda, sejauh yang saya tahu, adalah 'ini membingungkan dan buruk, ya, tapi tidak terlalu membingungkan dan buruk'.

Tidak, itu sama sekali bukan argumen saya. Saya melakukan yang terbaik dengan kecacatan yang saya miliki, tetapi ini bukan komunikasi yang saya maksudkan.

Jika Anda mencari 'rune Unicode' di Google, apa pun yang berhubungan dengannya dengan poin kode tidak akan muncul hingga halaman 2, dan itu pun hanya tautan godoc / Nim.

Jika Anda mencari 'Unicode string' di Google, Anda juga tidak akan mendapatkan secara spesifik cara kerja string .NET. Ini adalah masalah mencari hal yang berdekatan. Sebagai analogi yang sangat ketat, saya memprogram dalam .NET dan Ada; string tidak sama di antara mereka, dan sedikit bacaan untuk masing-masing adalah ide yang bagus.

Definisi yang berlebihan bukanlah hal yang aneh dalam bahasa, namun kami mengelola dengan baik. Ini mungkin mengejutkan Anda, tetapi "lari" memiliki setidaknya 179 definisi formal, "ambil" setidaknya 127, "break" setidaknya memiliki "123", dan seterusnya. [ sumber ] Orang-orang memiliki kemampuan yang luar biasa dan dapat dengan sukses menavigasi jauh lebih banyak kerumitan daripada apa yang dianggap bermasalah di sini. Kekhawatiran "rune" memiliki setidaknya 2 definisi formal, menurut pendapat saya, tidak dijamin ketika orang dapat ditunjukkan untuk menangani lebih dari 50x kelebihan beban.

Selain itu, ini sangat mengeksploitasi perilaku mesin pencari. Dengan sebagian besar mesin pencari, Anda mendapatkan hasil berdasarkan berapa banyak halaman yang tertaut ke sesuatu. Ada faktor-faktor lain juga, dengan masing-masing pendekatan memberikan bobot yang berbeda. Karena .NET Rune adalah konsep yang cukup baru sebagai perbandingan, akan ada jauh lebih sedikit konten yang membicarakannya, dan akan membutuhkan lebih banyak halaman untuk sampai ke sana. Tapi itu juga menggunakan alat pencarian yang salah. Jika saya ingin mencari penelitian tentang algoritma pencarian string, untuk melihat apakah sesuatu yang baru telah muncul dalam beberapa tahun terakhir, saya tidak mencari Google atau DDG. Cendekia Semantik, Google Cendekia, dan lainnya adalah titik awal yang lebih baik. Demikian pula, jika Anda ingin memahami hal-hal tentang .NET API, Anda mencari MSDocs terlebih dahulu. Jika saya mengeluh bahwa "momen inersia", istilah fisika/teknik, tidak jelas atau menyesatkan dalam namanya, dan harus diganti namanya karena saya tidak dapat menemukan informasi apa pun tentangnya di beberapa buku pertama, mulai dari angka terendah di perpustakaan menggunakan Klasifikasi Desimal Dewey, itu tidak masalah dengan penamaan "momen inersia"; Saya jelas mencari di tempat yang salah.

Sumber: Saya telah menggunakan Go dan saya pikir itu adalah grafem sampai empat tahun kemudian ketika saya membaca edisi ini sekarang.

Saya melihat-lihat dokumen Go dan catatan rilis, setidaknya yang dapat saya temukan, dan saya harus setuju dengan Anda. Mereka sangat tidak jelas tentang apa itu rune , dan sayangnya bahkan tidak jelas tentang seberapa besar rune itu. Saya menduga ketidakjelasan ini akan menyebabkan masalah di kemudian hari, karena saya telah melihat Ada yang sama samarnya tentang batasan tipe data dan membuatnya menggigit dirinya sendiri bertahun-tahun kemudian.

Namun saya harus mengatakan msdocs melakukan pekerjaan yang jauh lebih baik dengan deskripsi yang sangat rinci dan ringkas.

Mewakili nilai skalar Unicode ([ U+0000..U+D7FF ], inklusif; atau [ U+E000..U+10FFFF ], inklusif).

Ini dikatakan, komentarnya agak kurang dan beberapa penjelasan tentang mengapa Rune ada dan ketika Anda ingin menggunakannya akan bermanfaat (dan juga tempat yang tepat untuk penjelasan yang lebih rinci daripada yang saya sebutkan di atas) . Saya akan mengajukan beberapa perbaikan di sana.

@Evrey

Hanya demi argumen, dan untuk tujuan ilmiah, saya ingin menunjukkan kepada semua orang di sini pada satu bahasa pemrograman yang paling baik menangani teks Unicode

Ini adalah sebuah opini. Satu yang saya sangat setuju; Swift tentu saja menangani UNICODE modern dengan lebih baik. Tetapi tanpa kutipan dari penelitian yang dapat direproduksi oleh peer-review yang mengkonfirmasi hasil ini, ini bukan klaim ilmiah.

Sekarang, saya di sini tidak menyarankan agar C# menggunakan gaya Swift penuh. Meskipun ini akan luar biasa, ini juga membutuhkan banyak perubahan dan pekerjaan.

Dan akan merusak software yang ada.

biarkan opsi terbuka untuk mengubah string teks menjadi gaya Swift pada akhirnya.

Dan akan merusak software yang ada.

Ya, nama System.Rune sudah ada di luar sana. Semua ini hanyalah sebuah »jika kita ingin membuatnya lebih baik sebelum benda ini berumur setengah dekade«.

Dan akan merusak software yang ada.

Sebagai hipotetis jika perubahan harus dilakukan pada nama yang ada, bagaimana Anda mengusulkan penargetan perangkat lunak yang ada .NET Core 3.0/3.1, di mana Rune sudah digunakan, masih kompatibel, sementara juga ada sebagai nama yang berbeda di runtime target selanjutnya?

Dan akan merusak software yang ada.

Seperti yang disebutkan, saya hanya berdebat dari perspektif prinsip dan idealisme. Realitas banyak hal telah disebutkan. Meskipun ada beberapa nuansa untuk semua itu:

  • Menggunakan gaya Swift dengan string tidak serta merta merusak perangkat lunak. Ini hanya masalah menambahkan lebih banyak metode dan tipe enumerasi di atas antarmuka String yang sudah ada. Saya tidak bermaksud hal-hal radikal seperti mengubah System.Char menjadi tipe cluster grapheme atau semacamnya dengan itu.
  • Jika nama tipe yang ada seperti System.Char akan digunakan kembali untuk tipe yang berbeda, maka ya, itu akan menjadi perubahan besar yang melanggar. Dan perubahan yang tidak bertanggung jawab pada saat itu. Aku bersamamu di sana.
  • .NET Core 4.0 hipotetis, berbicara dalam SemVer, dapat melakukan apa pun yang diinginkannya. Selain itu, perubahan hingga 4.0 hipotetis tidak terlalu menakutkan: Ubah System.Rune menjadi tipe alias yang tidak digunakan lagi untuk System.UnicodeScalar atau apa pun namanya. Perangkat lunak yang menggunakan Rune tidak akan melihat perbedaan, selain dari catatan penghentian, dan perangkat lunak baru dapat menggunakan jenis sebenarnya dengan nama yang lebih baik. Dan 4.0 hipotetis kemudian turun begitu saja Rune .
  • Demikian pula, System.Char dapat diubah menjadi alias untuk System.CodeUnit16 atau sesuatu.
  • Melakukannya dengan gaya Swift secara efektif berarti menambahkan System.GraphemeCluster ke dalam campuran.
  • Pengenalan lebih banyak, alias kata kunci baru untuk semua jenis ini mungkin bermasalah.

Hanya menjatuhkan makanan untuk dipikirkan di sini. Saya pikir System.Rune , sementara nama jenis yang buruk untuk tujuannya, tidak benar-benar membuat status quo penamaan sebelumnya lebih buruk. Saya pikir sangat bagus bahwa akhirnya ada tipe yang tepat yang dapat menyandikan semua skalar Unicode. Namun, saya melihat peluang bagus untuk menyebarkan tren penanganan dan penamaan Unicode yang lebih akurat. Sebuah kesempatan yang semua orang di sini bebas untuk sisihkan.

Hai semua - nama System.Text.Rune adalah apa yang dikirimkan dan apa yang kami gunakan di masa mendatang. Ada diskusi yang signifikan (dan panas!) sebelumnya menggunakan nama UnicodeScalar bukannya Rune , tetapi pada akhirnya Rune menang. Tim tidak menyukai gagasan untuk memilih nama yang berbeda untuk saat ini. Dan sementara saya tahu orang-orang bersemangat tentang ini dan kami akan terus memantau percakapan di sini, pada akhirnya perlu diketahui bahwa setiap energi yang dihabiskan untuk melanjutkan litigasi masalah penamaan tidak akan menghasilkan dividen.

Untuk klarifikasi, dan menurut dokumen: tipe System.Text.Rune di .NET sama persis dengan nilai skalar Unicode. Ini ditegakkan dengan konstruksi. Ini membuatnya lebih analog dengan tipe UnicodeScalar Swift daripada tipe rune Go.

Ada upaya yang sedang dilakukan untuk menambahkan bagian ke dokumen Rune yang merinci kasus penggunaannya dan bagaimana kaitannya dengan API pemrosesan teks lain di .NET dan konsep di Unicode. Masalah pelacakan ada di https://github.com/dotnet/docs/issues/15845. Ada juga tautan dari masalah pelacakan itu ke draf dokumen konsep saat ini.

Bagi saya kelemahan utama dengan UnicodeScalar adalah perbedaan besar antara panjang nama tipe dan ukuran data tipe. Pada dasarnya ini adalah int dengan beberapa celah di domainnya.

Namun, verboseness dalam penggunaan akan menjadi ekstrim:

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

vs setara char lebih dari string (dan idealnya orang akan menggunakan tipe baru lebih dari char karena mereka adalah nilai keseluruhan daripada berisi nilai split)

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

Rune adalah kompromi dalam verboseness nama tipe:

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

@GrabYourPitchforks

Halo! Sejujurnya, saya terjebak dalam argumen ini bukan karena saya mencoba meyakinkan orang-orang .NET bahwa nama itu perlu diubah, karena tampaknya kapal itu telah berlayar, tetapi hanya karena saya ingin menyampaikan pendapat saya kepada orang lain di utas ini yang tidak setuju dengannya. Saya pikir itu luar biasa bahwa C# akhirnya memiliki tipe karakter _real_ sebagai lawan dari tipe karakter rusak yang telah begitu lama, dan nama sepenuhnya sekunder untuk itu. Saya mengerti bahwa ada keseimbangan besar yang harus dicapai antara singkatnya dan akurasi, dan meskipun saya akan menempatkan sweet spot di suatu tempat di sekitar CodePoint , saya mengerti mengapa orang lain tidak setuju.

Tetapi sekali lagi, saya ingin berterima kasih atas semua kerja keras dalam memodernisasi dukungan Unicode .NET! Ini adalah sesuatu yang membuat perbedaan besar bagi banyak orang di seluruh dunia.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat