Saya memiliki persyaratan yang relatif tidak jelas, tetapi rasanya harus memungkinkan menggunakan BCL.
Untuk konteks, saya mengurai string tanggal / waktu dalam Waktu Noda . Saya mempertahankan kursor logis untuk posisi saya dalam string input. Jadi, sementara string lengkapnya mungkin "3 Januari 2013" kursor logisnya mungkin berada di 'J'.
Sekarang, saya perlu mengurai nama bulan, membandingkannya dengan semua nama bulan yang diketahui untuk budaya:
- Peka budaya
- Tidak peka kasus
- Hanya dari titik kursor (bukan nanti; saya ingin melihat apakah kursor "melihat" nama bulan kandidat)
- Segera
- ... dan saya perlu tahu setelah itu berapa banyak karakter yang digunakan
The kode saat untuk melakukan hal ini umumnya bekerja, menggunakan CompareInfo.Compare
. Ini efektif seperti ini (hanya untuk bagian yang cocok - ada lebih banyak kode di hal yang nyata, tetapi tidak relevan dengan kecocokan):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Namun, itu bergantung pada kandidat dan wilayah yang kami bandingkan memiliki panjang yang sama. Baik-baik saja di sebagian besar waktu, tetapi tidak baik dalam beberapa kasus khusus. Misalkan kita memiliki sesuatu seperti:
// U+00E9 is a single code point for e-acute
var text = "x b\u00e9d y";
int position = 2;
// e followed by U+0301 still means e-acute, but from two code points
var candidate = "be\u0301d";
Sekarang perbandingan saya akan gagal. Saya bisa menggunakan IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
tapi:
- Itu mengharuskan saya membuat substring, yang sebaiknya saya hindari. (Saya melihat Noda Time secara efektif sebagai pustaka sistem; kinerja parsing mungkin penting untuk beberapa klien.)
- Itu tidak memberi tahu saya seberapa jauh untuk memajukan kursor sesudahnya
Pada kenyataannya, saya sangat curiga ini tidak akan sering muncul ... tetapi saya benar - benar ingin melakukan hal yang benar di sini. Saya juga sangat ingin dapat melakukannya tanpa menjadi ahli Unicode atau menerapkannya sendiri :)
(Dibesarkan sebagai bug 210 di Noda Time, jika ada yang ingin mengikuti kesimpulan akhirnya.)
Saya suka ide normalisasi. Saya perlu memeriksanya secara rinci untuk a) kebenaran dan b) kinerja. Dengan asumsi saya dapat membuatnya berfungsi dengan benar, saya masih tidak yakin bagaimana apakah itu layak untuk diubah secara keseluruhan - ini adalah jenis hal yang mungkin tidak akan pernah benar-benar muncul dalam kehidupan nyata, tetapi dapat merusak kinerja semua pengguna saya: (
Saya juga telah memeriksa BCL - yang tampaknya tidak menangani ini dengan baik. Kode sampel:
using System;
using System.Globalization;
class Test
{
static void Main()
{
var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
var months = culture.DateTimeFormat.AbbreviatedMonthNames;
months[10] = "be\u0301d";
culture.DateTimeFormat.AbbreviatedMonthNames = months;
var text = "25 b\u00e9d 2013";
var pattern = "dd MMM yyyy";
DateTime result;
if (DateTime.TryParseExact(text, pattern, culture,
DateTimeStyles.None, out result))
{
Console.WriteLine("Parsed! Result={0}", result);
}
else
{
Console.WriteLine("Didn't parse");
}
}
}
Mengubah nama bulan khusus menjadi hanya "tempat tidur" dengan nilai teks "bEd" akan menguraikan dengan baik.
Oke, beberapa poin data lagi:
Biaya penggunaan
Substring
danIsPrefix
signifikan tetapi tidak mengerikan. Pada contoh "Jumat 12 April 2013 20:28:42" di laptop pengembangan saya, itu mengubah jumlah operasi parse yang dapat saya jalankan dalam sedetik dari sekitar 460K menjadi sekitar 400K. Saya lebih suka menghindari perlambatan itu jika memungkinkan, tetapi itu tidak terlalu buruk.Normalisasi kurang layak dari yang saya kira - karena tidak tersedia di Perpustakaan Kelas Portabel. Saya berpotensi menggunakannya hanya untuk build non-PCL, memungkinkan build PCL menjadi sedikit kurang tepat. Hit kinerja pengujian untuk normalisasi (
string.IsNormalized
) menurunkan kinerja menjadi sekitar 445K panggilan per detik, yang dapat saya tangani. Saya masih tidak yakin itu melakukan semua yang saya butuhkan - misalnya, nama bulan yang mengandung "ß" harus cocok dengan "ss" di banyak budaya, saya percaya ... dan normalisasi tidak melakukan itu.
text
tidak terlalu lama, Anda bisa melakukannya if (compareInfo.IndexOf(text, candidate, position, options) == position)
. msdn.microsoft.com/en-us/library/ms143031.aspx Tapi jika text
sangat lama itu akan membuang banyak waktu untuk mencari di luar yang dibutuhkan.
String
kelas sama sekali dalam contoh ini dan gunakan secara Char[]
langsung. Anda akhirnya akan menulis lebih banyak kode, tetapi itulah yang terjadi ketika Anda menginginkan kinerja tinggi ... atau mungkin Anda harus memprogram dalam C ++ / CLI ;-)