Nispeten belirsiz bir gereksinimim var, ancak BCL kullanılarak mümkün olması gerektiği gibi geliyor .
Bağlam için, Noda Time'da bir tarih / saat dizesini ayrıştırıyorum . Giriş dizesi içindeki konumum için mantıksal bir imleç tutuyorum. Dolayısıyla, dizenin tamamı "3 Ocak 2013" olsa da, mantıksal imleç "J" konumunda olabilir.
Şimdi, ay adını, kültürün bilinen tüm ay adlarıyla karşılaştırarak ayrıştırmam gerekiyor:
- Kültüre duyarlı
- Büyük / küçük harf duyarsız
- Sadece imlecin bulunduğu noktadan (daha sonra değil; imlecin aday ay adına "bakıp bakmadığını" görmek istiyorum)
- Hızlı bir şekilde
- ... ve daha sonra kaç karakterin kullanıldığını bilmem gerekiyor
Bunu yapmak için mevcut kod genellikle CompareInfo.Compare
. Etkili bir şekilde şöyle (sadece eşleşen kısım için - gerçek şeyde daha fazla kod var, ancak maçla alakalı değil):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Ancak bu, adaya ve karşılaştırdığımız bölgenin aynı uzunlukta olmasına bağlıdır. Çoğu zaman iyidir , ancak bazı özel durumlarda iyi değildir . Şöyle bir şeye sahip olduğumuzu varsayalım:
// 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";
Şimdi karşılaştırmam başarısız olacak. Kullanabilirim IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
fakat:
- Bu, gerçekten kaçınmayı tercih ettiğim bir alt dize oluşturmamı gerektiriyor. (Noda Time'ı etkili bir sistem kitaplığı olarak görüyorum; performansın ayrıştırılması bazı istemciler için önemli olabilir.)
- Daha sonra imleci ne kadar ilerleteceğimi söylemiyor
Gerçekte, şiddetle bu çok sık gelip olmaz sanıyorum ... ama gerçekten istiyorum gibi burada doğru olanı yapmak için. Ayrıca bunu bir Unicode uzmanı olmadan ya da kendim uygulamadan da yapabilmeyi gerçekten çok isterim :)
( Herhangi birinin nihai bir sonucu takip etmek istemesi durumunda, Noda Time'da hata 210 olarak yükseltildi .)
Normalleşme fikrini seviyorum. Bunu a) doğruluk ve b) performans açısından ayrıntılı olarak kontrol etmem gerekiyor. Doğru çalışmasını sağlayabileceğimi varsayarsak , yine de her şeyi değiştirmeye değip değmeyeceğinden emin değilim - bu muhtemelen gerçek hayatta asla ortaya çıkmayacak , ancak tüm kullanıcılarımın performansına zarar verebilecek türden bir şey : (
BCL'yi de kontrol ettim - bu da bunu doğru bir şekilde ele almıyor gibi görünüyor. Basit kod:
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");
}
}
}
Özel ay adını "bEd" metin değerine sahip "bed" olarak değiştirmek, iyi ayrıştırır.
Tamam, birkaç veri noktası daha:
Kullanma maliyeti
Substring
veIsPrefix
önemli ancak korkunç değildir. Geliştirme dizüstü bilgisayarımdaki "12 Nisan 2013 Cuma 20:28:42" örneğinde, bir saniyede gerçekleştirebileceğim ayrıştırma işlemlerinin sayısını yaklaşık 460K'dan yaklaşık 400K'ya değiştiriyor. Mümkünse bu yavaşlamadan kaçınmayı tercih ederim, ama çok da kötü değil .Normalleştirme düşündüğümden daha az uygulanabilir - çünkü Taşınabilir Sınıf Kitaplıklarında mevcut değil. Potansiyel olarak sadece PCL olmayan yapılar için kullanabilirim, bu da PCL yapılarının biraz daha az doğru olmasına izin verir. Normalleştirme (
string.IsNormalized
) testinin performans artışı, performansı saniyede yaklaşık 445K çağrıya düşürüyor ve bununla yaşayabiliyorum. Hâlâ ihtiyacım olan her şeyi yaptığından emin değilim - örneğin, "ß" içeren bir ay adının birçok kültürde "ss" ile eşleşmesi gerektiğine inanıyorum ... ve normalleştirmenin bunu yapmadığını düşünüyorum.
text
çok uzun değil, yapabileceğin if (compareInfo.IndexOf(text, candidate, position, options) == position)
. msdn.microsoft.com/en-us/library/ms143031.aspx Ama eğer text
çok uzunsa bu, ihtiyaç duyduğu yerin ötesinde arama yapmak için çok zaman kaybedecektir.
String
sınıfını hiç bu örnekte ve kullanma Char[]
doğrudan. Daha fazla kod yazacaksınız, ama yüksek performans istediğinizde olan budur ... veya belki de C ++ / CLI ;-) ile programlama yapmanız gerekir