Soru Vaka duyarsız 'İçerir (string)'


Aşağıdaki dönüşün gerçek olmasını sağlamanın bir yolu var mı?

string title = "ASTRINGTOTEST";
title.Contains("string");

Benim durum hassasiyeti ayarlamanıza izin veren bir aşırı yük yok gibi görünüyor. Şu anda onları ikisini de UPPERCASE, ama sadece aptalca (ki ben i18n yukarı ve aşağı kasa ile gelen sorunlar).

GÜNCELLEŞTİRME
Bu soru eskidir ve o zamandan beri tam olarak araştırmak istiyorsanız gerçekten çok büyük ve zor bir konu için basit bir cevap istediğimi fark ettim.
Çoğu durumda, tek dilli, İngilizce kod tabanlı bu cevap yeterli olacaktır. Şüpheleniyorum çünkü buraya gelen çoğu insan bu kategoriye giriyor, bu en popüler cevap.
Bu Ancak cevap, hem metinlerin aynı kültür olduğunu hem de bu kültürün ne olduğunu bildiğimizi fark edinceye kadar metin olgusunu duyarsızlaştıramayacağımız içsel problemi ortaya çıkarmaktadır. Bu belki daha az popüler bir cevaptır, ama bence bu daha doğru ve bu yüzden böyle işaretledim.


2420
2018-01-14 21:39


Menşei


Nasıl saçma? Dize üzerinde 2 geçiş yaptığınızı mı kastediyorsunuz? Büyük / küçük harf duyarlı olmayan karşılaştırmaların sadece iki adımı birleştirdiğini düşünürdüm. - Calyth
Onu worldwebz'de kullanacağım için yabancı karakterleri hesaba katmalıyım. Aşağıda yer alan bir cevapta belirtildiği gibi, aşağıdan yukarıya kayma gibi uluslararasılaşma sorunları da uluslararası bir sorun yaratmaktadır. - Boris Callens
Her iki dizenin üst gövdesi de aptaldır, çünkü iki yeni dizge oluşturursunuz ve daha sonra büyük / küçük harf duyarlı bir arama gerçekleştirirsiniz. Özellikle, bir dizi dizeyle arama yapıyorsanız ve arama veya kaynak terimlerini gereksiz olarak kullanırsanız, bunun gibi yeni dizeler oluşturmada gereksiz ek işlemler ve bellek vardır. StringComparison değerinin belirtilmesine izin veren IndexOf yöntemi daha iyidir. - Triynko
xkcd.com/979 - Francisco
@ColonelPanic: Doğru. Kültürü biliyorsanız, bu daha az sorun olur. Ama genellikle, ya bilmiyor ya da umursamıyorsun. - Boris Callens


Cevaplar:


Dize olup olmadığını sınamak için paragraph dizeyi içerir word (teşekkürler @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

Nerede culture örneğidir CultureInfo Metnin yazıldığı dili açıklar.

Bu çözüm hakkında şeffaf Dil bağımlılığı olan vaka duyarsızlığının tanımı. Örneğin, İngilizce dili karakterleri kullanır I ve i dokuzuncu mektubun büyük ve küçük harf versiyonları için ise, Türkçe dili bu karakterleri on birinci ve on ikinci harf 29 harfli alfabe. 'İ' nin Türkçe büyük harfli versiyonu 'İ' karakteridir.

Böylece dizeler tin ve TIN aynı kelime İngilizcedeama farklı kelimeler Türkçe olarak. Anladığım kadarıyla, biri 'ruh', diğeri ise bir onomatopoeia kelimesidir. (Türkler, yanılıyorsam lütfen düzeltin ya da daha iyi bir örnek önerelim)

Özetlemek gerekirse, 'sadece bu iki dizenin aynı fakat farklı durumlarda' sorusunu cevaplayabilirsiniz. metnin hangi dilde olduğunu biliyorsanız. Bilmiyorsan, kumar oynayacaksın. İngilizcenin yazılımdaki hegemonyası göz önüne alındığında, muhtemelen CultureInfo.InvariantCultureÇünkü tanıdık yollarla yanlış olur.


1088
2018-03-17 18:22



Neden olmasın culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Bu, doğru kültürü kullanır ve büyük / küçük harfe duyarlıdır, geçici küçük harfli dizeler ayırmaz ve küçük harfe dönüştürülüp dönüştürülmediği ile karşılaştırmanın her zaman büyük / küçük harfe duyarlı bir karşılaştırmayla aynı olup olmadığı sorusundan kaçınır. - Quartermeister
Bu çözüm, arama işlevinin ne olması gerektiğine dair bellek ayırmak suretiyle yığının gereksiz yere kirlenmesine neden olur. - JaredPar
ToLower () ile karşılaştırmak, iki farklı harf aynı küçük harfe sahip olduğunda büyük / küçük harf duyarsız bir IndexOf'den farklı sonuçlar verecektir. Örneğin, U + 0398 "Yunan Büyük Harfli Theta" ya da U + 03F4 "Yunan Büyük Harfli Theta Sembolü" ndeki ToLower () 'ın çağrılması, U + 03B8, "Yunan Küçük Harfli Theta" ile sonuçlanır, ancak büyük harfler farklı kabul edilir. Her iki çözüm de, U + 0073 "Latin Küçük Harf S" ve U + 017F "Latin Küçük Harf Uzun S" gibi, aynı büyük harfle küçük harfleri göz önünde bulundurarak IndexOf çözümü daha tutarlı görünüyor. - Quartermeister
Tamlık için +1 - uygun bir açıklama biçimiyle yanıtlar, kullanıcıların SO'dan gerçekten öğrenecekleri tek yoldur - TheGeekZn
Niçin "ddddfg" yazmadınız. IndexOf ("Df", StringComparison.OrdinalIgnoreCase)? - Chen


Kullanabilirsiniz String.IndexOf Yöntemi ve geçmek StringComparison.OrdinalIgnoreCase kullanılacak arama türü olarak:

string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Daha da iyisi, string için yeni bir uzantı yöntemi tanımlamaktır:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}

Bunu not et boş propagasyon  ?. Daha eski sürümler için C # 6.0'dan (VS 2015) beri kullanılabilir

if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;

KULLANIM:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);

2361
2018-01-14 21:44



Büyük dize uzantısı yöntemi! Kaynak dizgisini kontrol etmek için benim düzenledim .IndexOf () gerçekleştirirken herhangi bir nesne başvuru hatası oluşmasını engellemek için boş değil. - Richard Pursehouse
Bu, aynı cevabı verir paragraph.ToLower(culture).Contains(word.ToLower(culture)) ile CultureInfo.InvariantCulture ve herhangi bir yerelleştirme sorununu çözmez. Neden karmaşık şeyleri karıştırıyorsun? stackoverflow.com/a/15464440/284795 - Colonel Panic
@ColonelPanic ToLower sürüm, bir karşılaştırma / arama işleminde gereksiz olan 2 ayırmayı içerir. Neden ihtiyaç duymayan bir senaryoda gereksiz yere tahsis edilir? - JaredPar
@ İşe yaramaz çünkü işe yaramaz string bir IEnumerable<char> bu yüzden alt dizeleri bulmak için kullanamazsınız - JaredPar
Uyarı kelimesi: Varsayılan olarak string.IndexOf(string) geçerli kültürü kullanırken, geçerli kültürü kullanmaktır string.Contains(string) Sıralı karşılaştırıcı kullanmaktır. Bildiğimiz gibi, eski değiştirilemezken, eski, daha uzun bir aşırı yük seçmek olabilir. Bu tutarsızlığın bir sonucu aşağıdaki kod örneğidir: Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */ - Jeppe Stig Nielsen


Kullanabilirsiniz IndexOf() bunun gibi:

string title = "STRING";

if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
    // The string exists in the original
}

0 (sıfır) bir indeks olabileceğinden -1'e karşı kontrol edin.

MSDN

Bu dize bulunursa sıfır tabanlı dizin değeri veya -1 değeri   ya değilse. Değer String.Empty ise, dönüş değeri 0'dır.


203
2018-01-14 21:48





Regex kullanarak alternatif çözüm:

bool contains = Regex.IsMatch("StRiNG to search", "string", RegexOptions.IgnoreCase);

ihbar

@Hao'nun kendi yorumunda belirttiği gibi, bu çözümün yanlış sonuçlara yol açmasına neden olacak senaryolar vardır. Bu çözümü geliştirmeden önce ne yaptığınızı bildiğinizden emin olun.


116
2017-07-28 17:18



İyi Fikir, aynı zamanda RegexOptions gibi çok fazla bitlen birleşim var. RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant; yardım ederse kimse için. - Saravanan
Düzenleme için IsMatch kullanılmasına rağmen bu yöntemi tercih etmeliyim. - wonea
Daha da kötüsü, arama dizgisi bir düzenli ifade olarak yorumlandığından, bir dizi noktalama işareti hatalı sonuçlara neden olur (veya geçersiz bir ifade nedeniyle bir istisna tetikler). Aramayı deneyin "." içinde "This is a sample string that doesn't contain the search string". Veya aramayı deneyin "(invalid", bu konuda. - cHao
@cHao: Bu durumda, Regex.Escape yardımcı olabilir. Regex hala gerekli görünmüyor IndexOf / uzantı Contains basittir (ve tartışmalı olarak daha açık). - Dan Mangiarelli
Bu Regex çözümünün gitmenin en iyi yolu olduğunu ima etmediğimi unutmayın. Aslına bakılırsa, asıl gönderi verilen soruya verilen cevapların listesine "Aşağıdaki dönüşü gerçekleştirmenin bir yolu var mı?" - Jed


İlk önce dizeleri yukarı ya da aşağı çekebilirsiniz.

string title = "string":
title.ToUpper().Contains("STRING")  // returns true

Oops, az önce bunu gördü. Davaya duyarlı olmayan bir karşılaştırma *muhtemelen* Yine de aynısını yap, eğer performans bir sorun değilse, büyük harfli kopya oluşturma ve bunları karşılaştırarak bir sorun görmüyorum. Bir zamanlar bir vakaya duyarsız bir kez karşılaştığını yemin edebilirim ...


63
2018-01-14 21:42



İlginç bir şekilde, ToUpper () 'ın ToLower ()' ın bu tür bir senaryoda kullanılması önerildiğini gördüm, çünkü görünüşe göre ToLower () bazı kültürlerde "sadakati" kaybedebilir, yani iki farklı büyük harf karakteri aynı küçük harf. - Matt Hamilton
"Türkiye testi" için ara :) - Jon Skeet
Bazı Fransız yerellerinde, büyük harflerin aksanlıkları yoktur, bu nedenle ToUpper (), ToLower () 'dan daha iyi olmayabilir. Kullanılabilirlerse uygun araçları kullanacağımı söyleyebilirim - büyük küçük harf duyarsız. - Blair Conrad
ToUpper veya ToLower'ı kullanmayın ve Jon Skeet'in söylediklerini yapın - Peter Gfader
Bunu iki yıl sonra tekrar gördüm ve yeni bir not düştü ... yine de, dizeleri karşılaştırmanın daha iyi yolları olduğuna katılıyorum. Ancak, tüm programlar yerelleştirilmez (çoğu olmaz) ve birçoğu iç veya dış mekan uygulamalarıdır. Atışlı uygulamalar için en iyi tavsiye için kredi beklemem mümkün olduğu için ... Devam ediyorum: D - Ed S.


Yanıtla ilgili bir sorun, bir dizenin boş olması durumunda bir istisna atar olmasıdır. Bunu bir çek olarak ekleyebilirsiniz, böylece olmaz:

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
        return true;

    return source.IndexOf(toCheck, comp) >= 0;
} 

48
2017-12-07 21:11



ToCheck boş dize ise İçerdekiler dokümantasyonuna göre true olarak geri dönmesi gerekiyorsa: "Değer dizesi bu dizede gerçekleşirse true, yoksa değer boş dizgeyse (" "); aksi halde false olur. - amurra
Yukarıda amurra'nın yorumuna dayanarak önerilen kodun düzeltilmesi gerekmiyor mu? Ve bu kabul edilen cevaba eklenmemeli, böylece en iyi cevap ilk önce mi? - David White
Şimdi, kaynak boş bir dize veya neyin ne olduğuna bakmaksızın null olursa, bu durum true olarak geri döner. Bu doğru olamaz. Ayrıca, boş bir dize ve kaynak boş değilse, IndexOf zaten true değerini döndürür. Burada gerekli olan null için bir kontrol. (Source == null || value == null) false değerini döndürmesini öneririm; - Colin
Kaynak boş olamaz - Lucas
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck); - Kyle Delaney


StringExtension sınıfı ileriye doğru yoldur, tam bir kod örneği vermek için yukarıdaki birkaç gönderiyi birleştirdim:

public static class StringExtensions
{
    /// <summary>
    /// Allows case insensitive checks
    /// </summary>
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}

32
2017-11-18 16:48





Bu temiz ve basit.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)

31
2017-11-09 04:25



Bu olsa da, bir modele karşı eşleşecektir. Örneğinizde fileNamestr özel regex karakterleri vardır (ör. *, +, .vb.) sonra oldukça sürpriz olacaksınız. Bu çözümü yapmanın tek yolu uygun bir şekilde çalışıyor Contains fonksiyon kaçmak fileNamestr yaparak Regex.Escape(fileNamestr). - XåpplI'-I0llwlg'I -


OrdinalIgnoreCase, CurrentCultureIgnoreCase veya InvariantCultureIgnoreCase?

Bu eksik olduğundan, hangisinin ne zaman kullanılacağı ile ilgili bazı öneriler:

Dos

  • kullanım StringComparison.OrdinalIgnoreCase karşılaştırmalar için kültür-agnostic dize eşleştirmesi için güvenli varsayılan değer olarak.
  • kullanım StringComparison.OrdinalIgnoreCase karşılaştırmalar artan hız için.
  • kullanım StringComparison.CurrentCulture-based dize işlemleri Çıkışı kullanıcıya gösterdiğinde.
  • Değişkene dayalı dize işlemlerinin akım kullanımını değiştir dilbilimsel olmayan dili kullanmak StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase karşılaştırma ne zaman
    dilbilimsel olarak alakasız (örneğin sembolik).
  • kullanım ToUpperInvariant ziyade ToLowerInvariant ne zaman karşılaştırma için dizileri normalleştirme.

Yapılmaması Gerekenler

  • Açıkça olmayan dize işlemleri için aşırı yükleri kullanın veya dize karşılaştırma mekanizmasını dolaylı olarak belirtin.
  • kullanım StringComparison.InvariantCulture temelli dize
    çoğu durumda operasyonlar; birkaç istisnadan biri olurdu
    dilbilimsel olarak anlamlı fakat kültürel olarak agnostik veriler devam ediyor.

Bu kurallara dayanarak şunları kullanmalısınız:

string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
    // The string exists in the original
}

[YourDecision], yukarıdaki tavsiyelere bağlıdır.

kaynağın bağlantısı: http://msdn.microsoft.com/en-us/library/ms973919.aspx


24
2018-06-17 10:31



Ya sen her zaman bir ingiliz dizisi alacağını biliyorsan. hangisini kullanmalı? - BKSpurgeon
Eğer durum önemli değilse, @BKSpurgeon OrdinalIgnoreCase'i kullanırdım - Fabian Bigler