2016-01-12 29 views
21

Bu garip sorunu farkettim. Bir yanlış sonuç gibi geliyor banaString.StartsYunan dillerle çalışmıyor mu?

string line = "Mìng-dĕ̤ng-ngṳ̄"; 
string sub = "Mìng-dĕ̤ng-ngṳ"; 
line.Length 
15 
sub.Length 
14 
line.StartsWith(sub) 
false 

: Bu Vietnam (Google Translate göre) dize göz atın. Bu yüzden, char-by-char dizesini karşılaştıran özel StartWith işlevimi uygulamıyorum. Sanırım

public bool CustomStartWith(string parent, string child) 
{ 
    for (int i = 0; i < child.Length; i++) 
    { 
     if (parent[i] != child[i]) 
      return false; 
    } 
    return true; 
} 

Ve, bu işlevi çalıştırma sonuçları

CustomStartWith("Mìng-dĕ̤ng-ngṳ̄", "Mìng-dĕ̤ng-ngṳ") 
true 

Burada ne oluyor ?! Bu nasıl mümkün olabilir?

+3

kullanın değişmez bir kültürü. Örneğin, bkz. Http://stackoverflow.com/q/492799/1364007 –

+6

Vietnamca bilmiyorum. Sonun üzerinde bir çizgi var. Bu farklı bir harf yapmaz mı? * Düzenleme: * Uzunluğunu yazdırdığınızı özledim, ki bu satırın * başka * karakter olarak kabul edildiğini gösteriyor ... ilginç. –

+4

Bana öyle geliyor ki 'StartsWith()' Yanlış döndürmesi gerek, çünkü (Jonathon'un işaret ettiği gibi), 'satır' aslında 'sub' ile başlamıyor. –

cevap

37

StartsWith tarafından döndürülen sonuç doğrudur. Varsayılan olarak, çoğu dize karşılaştırma yöntemleri, düz bayt dizileri değil, geçerli kültürü kullanarak kültüre duyarlı karşılaştırmalar gerçekleştirir. line, sub ile aynı bayt dizisi ile başlamasına rağmen, temsil ettiği alt tabaka çoğu (veya tüm) kültürün altında eşdeğer değildir.

gerçekten aşırı kullanmak, düz bayt dizileri olarak dizeleri davranır bir karşılaştırma isterseniz:

line.StartsWith(sub, StringComparison.OrdinalIgnoreCase);    // true 

Burada daha var: küçük harf duyarsız olması

line.StartsWith(sub, StringComparison.Ordinal);      // true 

İsterseniz karşılaştırılması bilinen bir örnek: yukarıdaki örneklerde

var line1 = "café"; // 63 61 66 E9  – precomposed character 'é' (U+00E9) 
var line2 = "café"; // 63 61 66 65 301 – base letter e (U+0065) and 
         //     combining acute accent (U+0301) 
var sub = "cafe"; // 63 61 66 65 
Console.WriteLine(line1.StartsWith(sub));        // false 
Console.WriteLine(line2.StartsWith(sub));        // false 
Console.WriteLine(line1.StartsWith(sub, StringComparison.Ordinal)); // false 
Console.WriteLine(line2.StartsWith(sub, StringComparison.Ordinal)); // true 

, line2sub ile aynı bayt dizisi ile başlar, ardından son e'a uygulanacak bir akıcı vurgu (U + 0301) gelir. line1, é (U + 00E9) için precomposed character kullanır, bu nedenle bayt dizisi sub ile eşleşmez. Gerçek dünya semantiklerinde, café; e ve , ayrı karakterler olarak kabul edilir. Bu 'un, e ile başlayan bir çift karakter olarak temsil edilmesinin, sonuçları etkilememesi gereken kodlama şemasının (Unicode) bir iç uygulama ayrıntısı olduğu gösterilir. Bu, yukarıdaki örnek zıt café ve café; Bir ordinal (byte-by-byte) karşılaştırmayı özellikle amaçlamadıkça, farklı sonuçlar beklemez.

sizin örneğe bu açıklamayı uyarlanması:

string line = "Mìng-dĕ̤ng-ngṳ̄"; // 4D EC 6E 67 2D 64 115 324 6E 67 2D 6E 67 1E73 304 
string sub = "Mìng-dĕ̤ng-ngṳ"; // 4D EC 6E 67 2D 64 115 324 6E 67 2D 6E 67 1E73 

Her .NET karakter, değerleri yukarıdaki açıklamalar gösterilmektedir UTF-16 kod birimini temsil eder. İlk 14 kod birimi aynıdır, bu nedenle char-by-char karşılaştırmanız doğru olarak değerlendirilir (tıpkı StringComparison.Ordinal gibi). Bununla birlikte, line'daki 15. kod birimi, ṳ̄ vermek üzere önceki (U+1E73) ile birleştiren birleştirici makron, ◌̄ (U+0304) 'dur.

+5

Ancak StartsWith için varsayılan bir karşılaştırma nedir? Ayrıca, neden IgnoreCase kullanıyorsunuz, sadece Ordinal değil? Yazar olayı göz ardı etmeden sıralı karşılaştırmayı kullanır. –

+3

@VadimMartynov: Örneği 'Ordinal' kullanmak için güncelledim. Genişleyen açıklama. – Douglas

+1

Ayrıca, 'line1.StartsWith (line2) 'nin true (ve tersi) olduğunu da unutmayın,' line1.Equals (line2, StringComparison.InvariantCulture)' gibi [ve CurrentCulture en makul ayarlar için ... tek-argüman Eşittir, Ordinal] – Random832

9

Bu bir hata değil.String.StartsWith aslında iki dizginizin karakter karakterli kontrolünden çok daha akıllıdır. Mevcut kültürünüzü (dil ayarları vb.) Hesaba katar ve kasılmaları ve özel karakterleri hesaba katar. (ṳ̄ ile biten iki karaktere ihtiyaç duymaz. Tek olarak karşılaştırır).

Bu, tüm bu kültüre özgü ayarları almak istemiyorsanız ve sıralı karşılaştırma kullanarak kontrol etmek istiyorsanız, bunu karşılaştırıcıya bildirmeniz gerektiği anlamına gelir.

Bu, doğru bunu yapmanın yolu olduğunu (değil Douglas gibi, davayı görmezden mi!):

line.StartsWith(sub, StringComparison.Ordinal); 
+1

'u kullanıyor gibi görünüyor. Ama neden bu kültüre özgü ayarları hesaba katmak istemiyorsunuz? Vietnamca konuşamıyorum, bu iki Dizgiler önek-eşit olarak kabul edilmeli mi, değil mi? – Thilo

+0

Bu OP. Vietnames'i de bilmiyorum, ama bazen bir şekilde ve bir dahaki sefere karşılaştırmak istediğini anlayabiliyorum. Bu yüzden 'Ordinal' kullanarak karşılaştırmayı etkileyebilirsiniz. –

+0

Anladım. Tek söylediğim, OP'nin gerçekten gitmek için bir yol olup olmadığını dikkatle düşünmesi gerektiğidir. – Thilo