a

Câu hỏi Trường hợp không nhạy cảm 'Chứa (chuỗi)'


Có cách nào để làm cho sự trở lại sau đúng không?

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

Có vẻ như không phải là quá tải cho phép tôi đặt độ nhạy của trường hợp .. Hiện tại, tôi CẬP NHẬT cả hai, nhưng đó chỉ là ngớ ngẩn (theo đó tôi đề cập đến i18n vấn đề đi kèm với vỏ bọc lên xuống).

CẬP NHẬT
Câu hỏi này là cổ xưa và kể từ đó tôi đã nhận ra tôi đã yêu cầu một câu trả lời đơn giản cho một chủ đề thực sự rộng lớn và khó khăn nếu bạn quan tâm để điều tra nó đầy đủ.
Đối với hầu hết các trường hợp, các căn cứ mã tiếng Anh, đơn ngữ điều này câu trả lời sẽ là đủ. Tôi nghi ngờ vì hầu hết mọi người đến đây đều thuộc loại này, đây là câu trả lời phổ biến nhất.
Điều này tuy nhiên, câu trả lời mang lại vấn đề vốn có mà chúng ta không thể so sánh chữ hoa văn không nhạy cảm cho đến khi chúng ta biết cả hai văn bản là cùng một nền văn hóa và chúng ta biết văn hóa đó là gì. Đây có lẽ là câu trả lời ít phổ biến hơn, nhưng tôi nghĩ nó đúng hơn và đó là lý do tại sao tôi đánh dấu nó như vậy.


2420
2018-01-14 21:39


gốc


Làm thế nào là nó ngớ ngẩn? Bạn có nghĩa là bạn đang làm 2 lượt trên chuỗi? Tôi nghĩ các so sánh không phân biệt chữ hoa chữ thường chỉ kết hợp hai bước. - Calyth
Vì tôi sẽ sử dụng nó trên worldwebz, tôi phải tính đến các nhân vật nước ngoài. Như đã đề cập trong một câu trả lời dưới đây, upcasing cũng như downcasing cho các vấn đề quốc tế hóa. - Boris Callens
Trên vỏ cả hai chuỗi là ngớ ngẩn, bởi vì bạn tạo hai chuỗi mới và sau đó vẫn thực hiện tìm kiếm phân biệt chữ hoa chữ thường. Có quá trình xử lý và bộ nhớ bổ sung không cần thiết liên quan đến việc tạo các chuỗi mới như vậy, đặc biệt nếu bạn đang tìm kiếm thông qua một tập hợp các chuỗi và bạn tìm kiếm các thuật ngữ tìm kiếm hoặc nguồn một cách dư thừa. Phương thức IndexOf cho phép đặc tả của một giá trị StringComparison là tốt hơn. - Triynko
xkcd.com/979 - Francisco
@ColonelPanic: Đúng. Nếu bạn biết văn hóa, điều này trở nên ít vấn đề hơn. Nhưng thông thường, bạn không biết hoặc không quan tâm. - Boris Callens


Các câu trả lời:


Để kiểm tra xem chuỗi paragraph chứa chuỗi word (cảm ơn @QuarterMeister)

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

Ở đâu culture là trường hợp của CultureInfo mô tả ngôn ngữ mà văn bản được viết.

Giải pháp này minh bạch về định nghĩa về trường hợp vô cảm, phụ thuộc vào ngôn ngữ. Ví dụ, tiếng Anh sử dụng các ký tự I và i đối với các phiên bản chữ hoa và chữ thường của chữ cái thứ chín, trong khi ngôn ngữ Thổ Nhĩ Kỳ sử dụng các ký tự này cho chữ thứ mười hai và mười hai của bảng chữ cái dài 29 chữ cái của nó. Phiên bản chữ hoa chữ thường của chữ 'i' là ký tự không quen thuộc 'İ'.

Vì vậy, các chuỗi tin và TIN là cùng một từ bằng tiếng Anh, nhưng các từ khác nhau bằng tiếng Thổ Nhĩ kỳ. Theo tôi hiểu, người ta có nghĩa là 'tinh thần' và người kia là một từ ngữ tượng hình. (Turks, xin vui lòng sửa tôi nếu tôi sai, hoặc đề nghị một ví dụ tốt hơn)

Tóm lại, bạn chỉ có thể trả lời câu hỏi 'là hai chuỗi này giống nhau nhưng trong các trường hợp khác nhau' nếu bạn biết ngôn ngữ trong văn bản. Nếu bạn không biết, bạn sẽ phải đi một punt. Với quyền bá chủ của người Anh trong phần mềm, bạn có thể nên CultureInfo.InvariantCulture, bởi vì nó sẽ sai theo những cách quen thuộc.


1088
2018-03-17 18:22



Tại sao không culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Điều đó sử dụng văn hóa phù hợp và phân biệt chữ hoa chữ thường, nó không phân bổ các chuỗi chữ thường tạm thời và nó tránh câu hỏi liệu chuyển đổi thành chữ thường và so sánh luôn giống như so sánh phân biệt chữ hoa chữ thường hay không. - Quartermeister
Giải pháp này cũng gây ô nhiễm không cần thiết cho bộ nhớ bằng cách cấp phát bộ nhớ cho chức năng tìm kiếm - JaredPar
So sánh với ToLower () sẽ cho kết quả khác nhau từ một IndexOf không phân biệt chữ hoa chữ thường khi hai chữ cái khác nhau có cùng chữ thường. Ví dụ: gọi ToLower () trên U + 0398 "Chữ cái Hy Lạp Thư Theta" hoặc U + 03F4 "Chữ cái Hy Lạp Thư Theta Biểu tượng" kết quả bằng chữ U + 03B8, "Chữ nhỏ Hy Lạp Theta", nhưng chữ hoa được xem là khác nhau. Cả hai giải pháp xem xét các chữ thường với cùng một chữ cái vốn khác nhau, chẳng hạn như U + 0073 "Chữ cái nhỏ La tinh S" và U + 017F "Chữ cái nhỏ Latinh dài S", vì vậy giải pháp IndexOf có vẻ phù hợp hơn. - Quartermeister
1 cho sự hoàn chỉnh - câu trả lời với một hình thức giải thích thích hợp là cách duy nhất người dùng thực sự sẽ học hỏi từ SO - TheGeekZn
Tại sao bạn không viết "ddddfg" .IndexOf ("Df", StringComparison.OrdinalIgnoreCase)? - Chen


Bạn có thể sử dụng Phương thức String.IndexOf và vượt qua StringComparison.OrdinalIgnoreCase là loại tìm kiếm để sử dụng:

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

Thậm chí tốt hơn là xác định một phương pháp mở rộng mới cho chuỗi:

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

Lưu ý rằng NULL  ?. có sẵn từ C # 6.0 (VS 2015), dành cho các phiên bản cũ hơn

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

SỬ DỤNG:

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

2361
2018-01-14 21:44



Phương pháp mở rộng chuỗi tuyệt vời! Tôi đã chỉnh sửa của tôi để kiểm tra chuỗi nguồn không phải là null để ngăn chặn bất kỳ lỗi tham chiếu đối tượng xảy ra khi thực hiện .IndexOf (). - Richard Pursehouse
Điều này cho cùng một câu trả lời paragraph.ToLower(culture).Contains(word.ToLower(culture)) với CultureInfo.InvariantCulture và nó không giải quyết bất kỳ vấn đề địa phương hóa nào. Tại sao lại phức tạp hơn? stackoverflow.com/a/15464440/284795 - Colonel Panic
@ColonelPanic the ToLower phiên bản bao gồm 2 phân bổ không cần thiết trong hoạt động so sánh / tìm kiếm. Tại sao không cần phân bổ trong một kịch bản mà không yêu cầu nó? - JaredPar
@Seabiscuit không hoạt động vì string là một IEnumerable<char> do đó bạn không thể sử dụng nó để tìm chất nền - JaredPar
Một lời cảnh báo: Mặc định cho string.IndexOf(string) là sử dụng văn hóa hiện tại, trong khi mặc định cho string.Contains(string) là sử dụng so sánh thứ tự. Như chúng ta biết, trước đây có thể được thay đổi được chọn một quá tải lâu hơn, trong khi sau này không thể thay đổi. Một hệ quả của sự không nhất quán này là mẫu mã sau đây: 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


Bạn có thể dùng IndexOf() như thế này:

string title = "STRING";

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

Vì 0 (không) có thể là chỉ mục, bạn kiểm tra lại -1.

MSDN

Vị trí chỉ mục dựa trên số không nếu chuỗi đó được tìm thấy, hoặc -1   nếu không phải vậy. Nếu giá trị là String.Empty, giá trị trả về là 0.


203
2018-01-14 21:48





Giải pháp thay thế bằng Regex:

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

Để ý

Như @cao đã chỉ ra trong bình luận của mình, có những kịch bản đó sẽ gây ra giải pháp này để trả về kết quả không chính xác. Hãy chắc chắn rằng bạn biết những gì bạn đang làm trước khi bạn thực hiện giải pháp này một cách bất ngờ.


116
2017-07-28 17:18



Ý tưởng hay, chúng tôi cũng có rất nhiều sự kết hợp bit trong RegexOptions như RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant; cho bất cứ ai nếu giúp. - Saravanan
Phải nói rằng tôi thích phương pháp này mặc dù sử dụng IsMatch cho gọn gàng. - wonea
Điều tồi tệ hơn, vì chuỗi tìm kiếm được hiểu là regex, một số dấu chấm câu sẽ gây ra kết quả không chính xác (hoặc kích hoạt ngoại lệ do biểu thức không hợp lệ). Thử tìm kiếm "." trong "This is a sample string that doesn't contain the search string". Hoặc thử tìm kiếm "(invalid", cho vẫn đề đó. - cHao
@cHao: Trong trường hợp đó, Regex.Escape có thể giúp. Regex vẫn có vẻ không cần thiết khi IndexOf / sự mở rộng Contains rất đơn giản (và cho là rõ ràng hơn). - Dan Mangiarelli
Lưu ý rằng tôi đã không ngụ ý rằng giải pháp Regex này là cách tốt nhất để đi. Tôi chỉ đơn giản là thêm vào danh sách các câu trả lời cho câu hỏi ban đầu được đăng "Có cách nào để làm cho sự trở lại sau đúng không?". - Jed


Bạn có thể luôn luôn chỉ lên hoặc xuống các chuỗi đầu tiên.

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

Rất tiếc, chỉ thấy chút cuối cùng. Một so sánh không phân biệt chữ hoa chữ thường sẽ *có lẽ* vẫn làm như vậy, và nếu hiệu suất không phải là một vấn đề, tôi không thấy một vấn đề với việc tạo ra các bản sao in hoa và so sánh chúng. Tôi có thể thề rằng tôi đã từng thấy một trường hợp không phân biệt dạng chữ một lần ...


63
2018-01-14 21:42



Điều thú vị là, tôi đã thấy ToUpper () được đề nghị sử dụng ToLower () trong trường hợp này, bởi vì dường như ToLower () có thể "mất tính trung thực" trong một số nền văn hóa nhất định - tức là hai ký tự chữ hoa khác nhau ký tự chữ thường. - Matt Hamilton
Tìm kiếm "Turkey test" :) - Jon Skeet
Trong một số miền địa phương của Pháp, các chữ in hoa không có dấu phụ, do đó ToUpper () có thể không tốt hơn so với ToLower (). Tôi muốn nói sử dụng các công cụ thích hợp nếu chúng có sẵn - so sánh phân biệt dạng chữ. - Blair Conrad
Không sử dụng ToUpper hoặc ToLower, và làm những gì Jon Skeet nói - Peter Gfader
Chỉ cần nhìn thấy điều này một lần nữa sau hai năm và một downvote mới ... dù sao, tôi đồng ý rằng có những cách tốt hơn để so sánh dây. Tuy nhiên, không phải tất cả các chương trình sẽ được bản địa hóa (hầu hết là không) và nhiều chương trình là các ứng dụng nội bộ hoặc ứng dụng throwaway. Vì tôi khó có thể mong đợi tín dụng cho lời khuyên tốt nhất còn lại cho các ứng dụng throwaway ... Tôi đang di chuyển trên: D - Ed S.


Một vấn đề với câu trả lời là nó sẽ ném một ngoại lệ nếu một chuỗi là null. Bạn có thể thêm điều đó làm séc để nó không:

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



Nếu toCheck là chuỗi rỗng, nó cần trả về true trên tài liệu Contains: "true nếu tham số value xuất hiện trong chuỗi này, hoặc nếu giá trị là chuỗi rỗng (" "); ngược lại, false." - amurra
Dựa trên nhận xét của amurra ở trên, mã không được đề xuất cần được sửa? Và điều này không nên được thêm vào câu trả lời được chấp nhận, để đáp ứng tốt nhất là trước tiên? - David White
Bây giờ điều này sẽ trả về true nếu source là một chuỗi rỗng hoặc null không có vấn đề gì toCheck là. Điều đó không thể chính xác. Ngoài ra IndexOf đã trả về true nếu toCheck là một chuỗi rỗng và nguồn không phải là null. Những gì cần thiết ở đây là một kiểm tra cho null. Tôi đề nghị nếu (nguồn == null || giá trị == null) trả về false; - Colin
Nguồn không thể là null - Lucas
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck); - Kyle Delaney


Lớp StringExtension là con đường phía trước, tôi đã kết hợp một vài bài viết ở trên để đưa ra một ví dụ mã hoàn chỉnh:

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





Điều này là sạch sẽ và đơn giản.

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

31
2017-11-09 04:25



Điều này sẽ phù hợp với một mô hình, mặc dù. Trong ví dụ của bạn, nếu fileNamestr có bất kỳ ký tự regex đặc biệt nào (ví dụ: *, +, ., vv) sau đó bạn sẽ ở trong một bất ngờ khá. Cách duy nhất để làm cho giải pháp này hoạt động như một Contains chức năng là để thoát fileNamestr bằng cách làm Regex.Escape(fileNamestr). - XåpplI'-I0llwlg'I -


OrdinalIgnoreCase, CurrentCultureIgnoreCase hoặc InvariantCultureIgnoreCase?

Vì điều này bị thiếu, dưới đây là một số đề xuất về thời điểm sử dụng:

Dos

  • Sử dụng StringComparison.OrdinalIgnoreCase để so sánh làm mặc định an toàn của bạn cho kết hợp chuỗi văn hóa bất khả tri.
  • Sử dụng StringComparison.OrdinalIgnoreCase so sánh để tăng tốc độ.
  • Sử dụng StringComparison.CurrentCulture-based chuỗi hoạt động khi hiển thị đầu ra cho người dùng.
  • Chuyển đổi sử dụng hiện tại của các hoạt động chuỗi dựa trên bất biến văn hóa để sử dụng ngôn ngữ phi ngôn ngữ StringComparison.Ordinal hoặc là StringComparison.OrdinalIgnoreCase khi so sánh là
    ngôn ngữ không liên quan (ví dụ như biểu tượng).
  • Sử dụng ToUpperInvariant thay vì ToLowerInvariant khi nào chuẩn hóa các chuỗi để so sánh.

Không

  • Sử dụng quá tải cho các hoạt động chuỗi không rõ ràng hoặc ngầm định rõ cơ chế so sánh chuỗi.
  • Sử dụng StringComparison.InvariantCulture chuỗi dựa trên
    hoạt động trong hầu hết các trường hợp; một trong số ít ngoại lệ sẽ là
    kiên trì dữ liệu có ý nghĩa về mặt ngôn ngữ nhưng có tính thuyết phục về mặt văn hóa.

Dựa trên các quy tắc này, bạn nên sử dụng:

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

trong khi [YourDecision] phụ thuộc vào các khuyến nghị từ trên.

liên kết của nguồn: http://msdn.microsoft.com/en-us/library/ms973919.aspx


24
2018-06-17 10:31



nếu bạn biết bạn sẽ luôn nhận được một chuỗi tiếng anh. cái nào để sử dụng? - BKSpurgeon
@BKSpurgeon Tôi muốn sử dụng OrdinalIgnoreCase, nếu trường hợp không thành vấn đề - Fabian Bigler


Chỉ như thế này:

string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}

12
2017-07-13 09:54



Đây không phải là văn hóa cụ thể và có thể không thành công trong một số trường hợp. culture.CompareInfo.IndexOf (paragraph, word, CompareOptions.IgnoreCase) nên được sử dụng. - hikalkan
Tại sao tránh string.ToLower () khi so sánh chuỗi không phân biệt chữ hoa chữ thường? Tl; Tiến sĩ Đó là tốn kém bởi vì một chuỗi mới là "sản xuất". - Liam


Tôi biết rằng đây không phải là C #, nhưng trong khung công tác (VB.NET) đã có một chức năng như vậy

Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")

Biến thể C #:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");

10
2017-09-09 13:23



Bạn cũng biết nó hoạt động như thế nào trong nội bộ? - Boris Callens