SORU
12 NİSAN 2013, Cuma


Nasıl bir dize ortasından kültür duyarlı "başlar" işlemi gerçekleştirebilir miyim?

Daha az belirgin olan bir şartı var, ama sanki öyle gibigerekirOlası KORUYUCU kullanıyor.

Bağlam için, Noda Time zaman string bir tarih/ayrıştırma ediyorum. Giriş dizesi içinde benim konum için bir mantıksal imleç korumak. Tam dize olabilir yani iken "3 Ocak 2013" mantıksal imlecin olabilir ''. J

Şimdi, ay adı, kültür için bilinen tüm ay isimlerini karşı karşılaştırarak ayrıştırmak gerekiyor:

  • Kültür-hassas
  • Case-duyarsızca
  • İmleç nokta (daha sonra; eğer imleç "" aday ay adı) bakıyor . eğer görmek istiyorum sadece
  • Hızlı bir şekilde
  • ... ve pek çok karakter kullanılmış daha sonra bilmek istiyorum

Bunu yapmak için current code genel olarak, CompareInfo.Compare kullanarak çalışır. Bu (sadece eşleşen yarı gerçek bir şey daha kod var ama maç ile alakalı değil) etkili gibi:

internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
    return compareInfo.Compare(text, position, candidate.Length,
                               candidate, 0, candidate.Length, 
                               CompareOptions.IgnoreCase) == 0;
}

Ancak, aday dayanır ve aynı uzunlukta olmak karşılaştırırız bölge. İyi çoğu zaman amadeğilTamam bazı özel durumlarda. Biz bir şey gibi olduğunu 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 benim karşılaştırma başarısız olur. IsPrefix kullanabilirim:

if (compareInfo.IsPrefix(text.Substring(position), candidate,
                         CompareOptions.IgnoreCase))

ama:

  • Bu bana gerçekten oldukça uzak dururdum olan bir dize oluşturmak için gerektirir. (Bir sistem olarak etkili kütüphane Noda Zaman ilgilenen kulüpler; performans ayrıştırma bazı müşteriler için önemli olabilir.)
  • İmleci daha sonra Önceden bana nasıl söylemez

Gerçekte, bu çok sık gelmiyor şüphelendim... ama isterdim gerçektengibiburada doğru olanı yapmak için. Ayrıca gerçekten Unicode uzmanı olmak veya kendi kendime:) uygulama olmadan bunu yapmak mümkün olmak istiyorum

(Herkes, herhangi bir nihai sonuç takip etmek istiyor diye Noda bug 210 olarak yetiştirdi.)

Normalleştirme fikri hoşuma gitti. Ben ayrıntılı olarak kontrol etmek için bir ihtiyaç) doğruluğu ve b) performans. Ben Varsayarakolabilirdüzgün çalışması, yine de değer her yerinde değişen olacağını nasıl emin değilim - hangi bir şey muhtemelenaslagerçek hayatta da geldi, ama zarar verecek tüm kullanıcıların performans :(

Ayrıca bu doğru ya da işlemek için görünmüyor KORUYUCU - kontrol ettim. Örnek 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");
        }
    }
}

Sadece adı özel ay "" "" iyi. ayrıştırır yataktan metin değeri ile yatak değiştirme

Tamam, daha fazla veri birkaç nokta:

  • Substring IsPrefix kullanarak maliyeti önemli değil ama çok kötü. Bir örnek "12 2013 20:28:42 Cuma Nisan" kalkınma bilgisayarımda, ayrıştırma işlemlerinin sayısını değiştirir yaklaşık 400 k üzere 460 bin anında infaz ederim. Daha doğrusu mümkünse bu yavaşlama kaçınmak istiyorum, ama değilçokkötü.

  • Normalleştirme Taşınabilir Sınıf Kitaplıkları mevcut değil, çünkü düşündüğümden daha az mümkün. Onu kullanmak olabilirsadeceolmayan yapılar için PCL, PCL izin veren biraz daha az doğru oluşturur. Normalleşme için test performans isabet (string.IsNormalized) performans ile yaşayabilirim ki saniyede yaklaşık 445K aramalar, aşağı alır. Ben hala emin değilim öyle her şeye ihtiyacım var bunun için - örneğin, bir ay ismini içeren "ß" maç "ss" birçok kültür, inanıyorum... ve normalleştirme yok.

CEVAP
14 NİSAN 2013, Pazar


Birçok sorun olmaktan< edeceğim;->birçok/bir ilk ve ayrı ayrı farklı Normalleştirme formları taşıma casemappings.

Örneğin:

x heiße y
  ^--- cursor

Maçlar heisse ama o zaman çok fazla 1 imleç. Ve:

x heisse y
  ^--- cursor

Maçlar heiße ama sonra hamle imleç 1 çok az.

Bu basit bir bire-bir eşleme olmayan herhangi bir karakter için geçerli olacak.

Aslında eşleştirilen alt uzunluğu bilmek gerekir. Ama Compare, 22* ..*vb bu bilgileri çöpe atın. Bu uygulama tam bir vaka katlanır yapmaz ama düzenli ifadeler ile mümkün olabilir ve bu yüzden uyuşmuyor .Compare .IndexOf bile büyük / küçük harf duyarlı modu ss/SS 23*. Ve muhtemelen yeni yukarıdaki diyagram oluşturmak için pahalı olurdu her aday zaten.

Bu en kolay yol, sadece dahili dava katlanmış şeklinde dizeleri depolamak ve katlanmış durumda adaylar ile ikili karşılaştırmalar yapmak. Sonra imleci iç gösterimi beri imleci doğru sadece .Length ile hareket ettirin. Ayrıca kayıp performansı en olsun CompareOptions.IgnoreCase kullanmak zorunda değil.

Durum işlevi yerleşik ve zavallı adamın durumu katlama katlama diye bir şey yok ne yazık ki durum tam eşleme - ToUpper yöntemi yok çünkü çalışmıyor SS ß dönüş yok.

Örneğin bu Normal Form C dize verilen Java (Javascript) çalışır:

//Poor man's case folding.
//There are some edge cases where this doesn't work
public static String toCaseFold( String input, Locale cultureInfo ) {
    return input.toUpperCase(cultureInfo).toLowerCase(cultureInfo);
}

Java görmezden durumda karşılaştırması not için eğlenceli tam dava C gibi katlanır yapmaz#'CompareOptions.IgnoreCase ler. Bu konuda tam tersi yani: Java tam casemapping, ama basit bir vaka katlama - yok C# basit casemapping, ama tam bir vaka katlanır.

Dava için 3. parti bir kütüphane kullanmadan önce kendi dizeleri kat gerekir muhtemeldir ki.


Bir şey yapmadan önce ipleri C. şeklinde normal olduğundan emin olmak gerekir bu ön Hızlı check Latin yazısı için optimize edilmiş kullanabilirsiniz:

public static bool MaybeRequiresNormalizationToFormC(string input)
{
    if( input == null ) throw new ArgumentNullException("input");

    int len = input.Length;
    for (int i = 0; i < len;   i)
    {
        if (input[i] > 0x2FF)
        {
            return true;
        }
    }

    return false;
}

Bu yanlış pozitif ancak yanlış negatif, her dize yapılması gerekiyor olsa da, Latin alfabesi karakterleri kullanırken 460 bin ayrıştırır/s hiç yavaşlama beklemiyorum verir. Yanlış pozitif IsNormalized gerçek Negatif/Pozitif elde etmek için kullanmak ve gerekirse bundan sonra normalize olur.


Sonuç olarak, bu işlem normal form C ilk emin olmak için, o davayı katlayın. İşlenmiş dizeleri ile ikili karşılaştırmalar yapmak ve şu anda hareket ediyor gibi götürün.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • KarnasCamillo

    KarnasCamill

    24 EKİM 2007
  • Nightmare2005

    Nightmare200

    14 Ocak 2007
  • Simon Hayter

    Simon Hayter

    20 HAZİRAN 2010