ความแตกต่างระหว่าง InvariantCulture และการเปรียบเทียบสตริงสามัญ


548

เมื่อเปรียบเทียบสองสายใน c # เพื่อความเท่าเทียมกันความแตกต่างระหว่าง InvariantCulture และการเปรียบเทียบลำดับคืออะไร?


อาจจะเป็นsiao2.com/2004/12/29/344136.aspx ? (googled)
Daneish ชีส

2
สำหรับผู้ใช้String1.Equals(String2, StringComparison.Ordinal)ที่คุณใช้งานที่ดีString1 == String2ซึ่งเป็นพื้นฐานString1.Equals(String2)และเป็นค่าเริ่มต้นการเปรียบเทียบกรณีลำดับ
Ghasan

3
@Ghasan ไม่แน่ใจว่าที่ทำให้=="ดี" แต่มันเป็น) สั้นข) น้อยลงอย่างชัดเจนเกี่ยวกับสิ่งที่ว่ามันไม่และค) สามารถเป็นโมฆะโดยไม่ต้องเปรียบเทียบการขว้างปาString1 NullReferenceException
Eugene Beresovsky

3
@Ghasan แนวทางปฏิบัติที่ดีที่สุดของ MSDN อย่างเป็นทางการสำหรับการใช้สตริงในหน้า. NET Framework ( msdn.microsoft.com/en-us/library/ ...... ) แนะนำการใช้โอเวอร์โหลดที่ระบุStringComparisonประเภทอย่างชัดเจน String.Equalsในกรณีของการเปรียบเทียบสตริงก็หมายความว่า
Ohad Schneider

3
เพื่อหลีกเลี่ยงการ @EugeneBeresovsky คุณก็สามารถใช้วิธีการแบบคงที่:NullReferenceException String.Equals(string1, string2, StringComparison.Ordinal)
Ohad Schneider

คำตอบ:


302

InvariantCulture

ใช้ชุดอักขระลำดับ (มาตรฐาน) (a, b, c, ... ฯลฯ ) สิ่งนี้ตรงกันข้ามกับสถานที่เฉพาะบางแห่งซึ่งอาจจัดเรียงอักขระตามคำสั่งที่แตกต่างกัน ('a-with-acute' อาจเป็นก่อนหรือหลัง 'a' ขึ้นอยู่กับสถานที่และอื่น ๆ )

เกี่ยวกับลำดับ

ในอีกทางหนึ่งดูที่คุณค่าของไบต์ดิบที่แสดงถึงตัวละครอย่างหมดจด


มีตัวอย่างที่ยอดเยี่ยมที่http://msdn.microsoft.com/en-us/library/e6883c06.aspxซึ่งแสดงผลลัพธ์ของค่า StringComparison ต่างๆ ตลอดตอนท้ายมันแสดงให้เห็น (ข้อความที่ตัดตอนมา):

StringComparison.InvariantCulture:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

StringComparison.Ordinal:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

คุณสามารถเห็นได้ว่าที่อัตราผลตอบแทน InvariantCulture (U + 0069, U + 0049, U + 00131), อัตราผลตอบแทนปกติ (U + 0049, U + 0069, U + 00131)


25
การเปรียบเทียบลำดับจะดูที่จุดโค้ดไม่ใช่ไบต์
Joey

144
ฉันรู้สึกว่าเป็นข้อมูลที่มีประโยชน์ แต่ไม่ได้ตอบคำถาม เมื่อพิจารณาความเท่าเทียมกันของสองสายมีเหตุผลใดที่จะใช้ InvarintCulture แทน Ordinal? ดูเหมือนว่า InvariantCulture จะใช้ในการเรียงลำดับสตริงและควรใช้ Ordinal สำหรับการตรวจสอบความเท่าเทียมกัน (เราไม่สนใจว่าการเน้นเสียงมาก่อนหรือหลัง a มันแตกต่างกันเพียง) แม้ว่าฉันเองก็ไม่แน่ใจในประเด็นนี้
MPavlak

18
ดูmsdn.microsoft.com/en-us/library/ms230117%28v=vs.90%29.aspxและสังเกตว่าแนะนำให้ทำการปรับมาตรฐานสตริงและการเปรียบเทียบตามลำดับ
MPavlak

23
Ordinal เร็วกว่ามาก
Darren

9
มีผลการทดสอบประสิทธิภาพที่ดีที่เผยแพร่การทดสอบการเปรียบเทียบสตริง C #ซึ่งบอกประสิทธิภาพของวิธีการเปรียบเทียบสตริงที่แตกต่างกันและเวลาของพวกเขา
Kumar C

262

ยกตัวอย่างเช่นมันมีความสำคัญ - มีสิ่งหนึ่งที่เรียกว่าการขยายตัวของอักขระ

var s1 = "Strasse";
var s2 = "Straße";

s1.Equals(s2, StringComparison.Ordinal);           //false
s1.Equals(s2, StringComparison.InvariantCulture);  //true

ด้วยInvariantCultureอักขระßรับขยายเป็น ss


1
ไม่สิ่งนี้ยังแตกต่างกันในทางระหว่างบางOrdinalและInvariantCulture? นั่นคือสิ่งที่เป็นคำถามเดิมเกี่ยวกับ
Matthijs Wessels

3
สำหรับผู้ที่ไม่ทราบßว่าควรสังเกตว่าßอย่างน้อยในภาษาเยอรมันเท่ากับ s สองที่มา: en.wikipedia.org/wiki/%C3%9F
Peter

20
นั่นไม่ถูกต้อง @Peter คุณไม่สามารถใช้ßและssแลกเปลี่ยนเป็นภาษาเยอรมันได้ (ฉันเป็นเจ้าของภาษา) มีหลายกรณีที่ทั้งสองถูกกฎหมาย (แต่บ่อยครั้งที่ล้าสมัย / ไม่แนะนำ) และมีหลายกรณีที่อนุญาตให้ใช้แบบฟอร์มเดียวเท่านั้น
enzi

5
ตัวอย่างง่ายๆนี้แสดงให้เห็นอย่างชัดเจนถึงความแตกต่างระหว่างการเปรียบเทียบทั้งสอง ฉันคิดว่าฉันได้รับตอนนี้
BrianLegg

4
ต้องลอง: ideone.com/j8DvDoเจ๋งมาก! บทเรียนเล็กน้อยในภาษาเยอรมันเช่นกัน สงสัยว่าสิ่งที่แตกต่างระหว่างเอสเอสและเอสเอสในขณะนี้ ...
MZN

111

ชี้ไปที่วิธีปฏิบัติที่ดีที่สุดสำหรับการใช้สตริงใน. NET Framework :

  • ใช้StringComparison.OrdinalหรือStringComparison.OrdinalIgnoreCaseเปรียบเทียบเป็นค่าเริ่มต้นที่ปลอดภัยสำหรับการจับคู่สตริงที่ไม่เชื่อเรื่องพระเจ้า
  • ใช้การเปรียบเทียบกับStringComparison.OrdinalหรือStringComparison.OrdinalIgnoreCaseเพื่อประสิทธิภาพที่ดีขึ้น
  • ใช้ค่าที่ไม่ใช่ทางภาษาStringComparison.OrdinalหรือStringComparison.OrdinalIgnoreCaseค่าแทนที่จะใช้การดำเนินการกับสตริงตามCultureInfo.InvariantCultureเมื่อการเปรียบเทียบนั้นไม่เกี่ยวข้องกับภาษา (ตัวอย่างเช่นสัญลักษณ์)

และในที่สุดก็:

  • อย่าใช้การดำเนินการบนพื้นฐานของสตริงStringComparison.InvariantCultureในกรณีส่วนใหญ่ หนึ่งในข้อยกเว้นบางประการคือเมื่อคุณเก็บข้อมูลทางภาษาที่มีความหมาย แต่ไม่เชื่อเรื่องพระเจ้าเกี่ยวกับวัฒนธรรม

56

ความแตกต่างที่มีประโยชน์อื่น (เป็นภาษาอังกฤษที่เน้นเสียงผิดปกติ) คือการเปรียบเทียบ InvariantCulture เปรียบเทียบสตริงทั้งหมดโดยคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ก่อนจากนั้นถ้าจำเป็น (และร้องขอ) แยกความแตกต่างตามตัวอักษร (คุณยังสามารถทำเปรียบเทียบกรณีตายของหลักสูตรซึ่งจะไม่เห็นความแตกต่างจากกรณี.) ที่ถูกต้อง:ตัวอักษรที่เน้นเสียงจะถือเป็นอีกรสชาติของตัวอักษรเดียวกันและสตริงจะถูกเปรียบเทียบก่อนโดยไม่เน้นเครื่องหมายเน้นเสียงจากนั้นทำการบัญชีสำหรับพวกเขาหากตัวอักษรทั่วไปตรงกันทั้งหมด (เหมือนกับกรณีที่แตกต่างกันยกเว้นในท้ายที่สุด กลุ่มนี้เน้นเสียงของคำที่เหมือนกันเป็นอย่างอื่นซึ่งอยู่ใกล้กันแทนที่จะแยกจากกันโดยสิ้นเชิงในสำเนียงแรก นี่คือลำดับการเรียงที่คุณมักจะพบในพจนานุกรมโดยมีคำที่เป็นตัวพิมพ์ใหญ่ปรากฏขึ้นถัดจากตัวพิมพ์เล็กและตัวอักษรเน้นเสียงอยู่ใกล้กับตัวอักษรที่ไม่มีเครื่องหมายกำกับ

การเปรียบเทียบลำดับจะเปรียบเทียบอย่างเคร่งครัดกับค่าอักขระตัวเลขหยุดที่ความแตกต่างแรก การเรียงลำดับตัวอักษรตัวพิมพ์ใหญ่ทั้งหมดแยกจากตัวอักษรตัวเล็กอย่างชัดเจน (และตัวอักษรเน้นเสียงจะแยกจากตัวอักษรเหล่านั้น) ดังนั้นคำที่เป็นตัวพิมพ์ใหญ่จะเรียงลำดับใกล้เคียงกับตัวพิมพ์เล็กของพวกเขา

InvariantCulture ยังพิจารณาว่าตัวพิมพ์ใหญ่กว่าตัวพิมพ์เล็กในขณะที่ Ordinal จะถือว่าตัวพิมพ์เล็กกว่าตัวพิมพ์เล็ก (การครอบครอง ASCII จากสมัยก่อนก่อนที่คอมพิวเตอร์จะมีตัวอักษรตัวพิมพ์เล็กตัวอักษรตัวพิมพ์ใหญ่จะถูกจัดสรรเป็นอันดับแรก เพิ่มในภายหลัง)

ตัวอย่างเช่นโดย Ordinal: "0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"

และโดย InvariantCulture: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"


ฉันดูอีกครั้งและสังเกตเห็นความไม่ลงรอยกันระหว่างตัวอย่าง InvariantCulture และคำอธิบายของฉันเกี่ยวกับการจัดการอักขระที่เน้นเสียง ตัวอย่างนี้ดูเหมือนจะถูกต้องดังนั้นฉันจึงแก้ไขคำอธิบายให้สอดคล้องกัน การเปรียบเทียบ InvariantCulture ไม่ได้หยุดที่สำเนียงที่แตกต่างกันในตอนแรกและดูเหมือนจะพิจารณาเฉพาะความแตกต่างของสำเนียงในตัวอักษรเดียวกันถ้าส่วนที่เหลือของสตริงตรงกับสำเนียงและตัวพิมพ์ใหญ่ ความแตกต่างของสำเนียงจะถูกพิจารณาก่อนความแตกต่างของกรณีก่อนหน้าดังนั้น "Aaba" <"aába"
Rob Parker

31

แม้ว่าคำถามจะเกี่ยวกับความเท่าเทียมกันแต่สำหรับการอ้างอิงด้วยภาพอย่างรวดเร็วนี่คือคำสั่งของสตริงบางส่วนที่จัดเรียงโดยใช้สองวัฒนธรรมที่แสดงถึงความแปลกแยกบางอย่างออกมา

Ordinal          0 9 A Ab a aB aa ab ss Ä Äb ß ä äb      
IgnoreCase       0 9 a A aa ab Ab aB ss ä Ä äb Äb ß      
--------------------------------------------------------------------
InvariantCulture 0 9 a A  ä Ä aa ab aB Ab äb Äb ss ß     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ß ss     
--------------------------------------------------------------------
da-DK            0 9 a A  ab aB Ab ss ß ä Ä äb Äb aa     
IgnoreCase       0 9 A a  Ab aB ab ß ss Ä ä Äb äb aa     
--------------------------------------------------------------------
de-DE            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
en-US            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
ja-JP            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     

ข้อสังเกต:

  • de-DE, ja-JPและen-USการจัดเรียงในลักษณะเดียวกัน
  • Invariantเรียงลำดับssและßแตกต่างจากสามวัฒนธรรมข้างต้นเท่านั้น
  • da-DK จัดเรียงค่อนข้างแตกต่างกัน
  • IgnoreCaseเรื่องธงวัฒนธรรมตัวอย่างทั้งหมด

รหัสที่ใช้สร้างตารางด้านบน:

var l = new List<string>
    { "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß",
      "Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" };

foreach (var comparer in new[]
{
    StringComparer.Ordinal,
    StringComparer.OrdinalIgnoreCase,
    StringComparer.InvariantCulture,
    StringComparer.InvariantCultureIgnoreCase,
    StringComparer.Create(new CultureInfo("da-DK"), false),
    StringComparer.Create(new CultureInfo("da-DK"), true),
    StringComparer.Create(new CultureInfo("de-DE"), false),
    StringComparer.Create(new CultureInfo("de-DE"), true),
    StringComparer.Create(new CultureInfo("en-US"), false),
    StringComparer.Create(new CultureInfo("en-US"), true),
    StringComparer.Create(new CultureInfo("ja-JP"), false),
    StringComparer.Create(new CultureInfo("ja-JP"), true),
})
{
    l.Sort(comparer);
    Console.WriteLine(string.Join(" ", l));
}

1
อืม - โอเคมันดีที่คุณทำวิจัยนี้และโพสต์สิ่งที่คุณพบแม้ว่าฉันไม่แน่ใจว่าประเด็นของคุณคืออะไร อย่างไรก็ตามเดนมาร์กอาจไม่ใช่หนึ่งใน "วัฒนธรรมที่สำคัญที่สุด" (แม้ว่าเดนมาร์กกว่า 5 ล้านคนจะค่อนข้างชื่นชอบวัฒนธรรมของพวกเขา) แต่ถ้าคุณโยน "aa" ลงในสตริงการทดสอบเพิ่มเติมและ "da-DK" ในฐานะ วัฒนธรรมการทดสอบเพิ่มเติมคุณจะเห็นผลลัพธ์ที่น่าสนใจ
RenniePet

1
@ ReniePet ขอบคุณสำหรับสิ่งนั้น ฉันเพิ่มภาษาเดนมาร์กเนื่องจากมันค่อนข้างแตกต่างจาก 3 วัฒนธรรมอื่น ๆ ที่ใช้ (เนื่องจากอิโมติคอนที่บ่งชี้ว่าประชดดูเหมือนจะไม่เข้าใจในเว็บการอ่านภาษาอังกฤษอย่างที่ฉันคิดเอาออกความคิดเห็น "วัฒนธรรมที่สำคัญที่สุด" หลังจากทั้งหมด BCL ไม่ได้มีลักษณะCultureComparerที่เราสามารถใช้ เพื่อตรวจสอบสำหรับตารางนี้Danishวัฒนธรรม (ข้อมูล) กลายเป็นเรื่องสำคัญมาก)
Eugene Beresovsky

1
ขอบคุณ ฉันได้ตระหนักว่าความคิดเห็น "วัฒนธรรมที่สำคัญที่สุด" ของคุณนั้นตั้งใจจะเอามาใส่เกลือเม็ด - มันแค่ว่าฉันแก่เกินไปที่จะใช้อิโมติคอน ฉันคิดว่าการส่งข้อความกลายเป็นเรื่องธรรมดาที่การใช้อีโมติคอนนั้นเหมือนกับการอธิบายเรื่องตลกของคุณหลังจากที่คุณบอกพวกเขาโดยไม่คำนึงว่าจะมีใครหัวเราะหรือไม่ก็ตาม อนึ่งวัฒนธรรมสแกนดิเนเวียอื่น ๆ (ฟินแลนด์นอร์เวย์และสวีเดน) จะเหมือนกับเดนมาร์กยกเว้นการจัดการ "aa" พิเศษซึ่งพิสูจน์ว่าเดนมาร์กเป็นวัฒนธรรมที่เหนือกว่าแน่นอน
RenniePet

1
สำหรับสิ่งที่คุ้มค่าภาษาเดนมาร์กจะจัดเรียงäและ aa แตกต่างกันเนื่องจากตำแหน่งของตัวอักษรพิเศษæ (ae), ø (oe, ö) และå (aa, ä) ที่ส่วนท้ายของตัวอักษรตามลำดับที่เขียน
Alrekr


5

นี่คือตัวอย่างที่การเปรียบเทียบความเท่าเทียมกันของสตริงโดยใช้ InvariantCultureIgnoreCase และ OrdinalIgnoreCase จะไม่ให้ผลลัพธ์เดียวกัน:

string str = "\xC4"; //A with umlaut, Ä
string A = str.Normalize(NormalizationForm.FormC);
//Length is 1, this will contain the single A with umlaut character (Ä)
string B = str.Normalize(NormalizationForm.FormD);
//Length is 2, this will contain an uppercase A followed by an umlaut combining character
bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase);
bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase);

หากคุณดำเนินการนี้เท่ากับ 1 จะเป็นเท็จและเท่ากับ 2 จะเป็นจริง


เพียงเพื่อเพิ่มอีกตัวอย่างที่คล้ายกัน แต่มีตัวอักษรสตริงถ้าa="\x00e9"(เฉียบพลัน) และb="\x0065\x0301"(รวมกับสำเนียงเฉียบพลัน) StringComparer.Ordinal.Equals(a, b)จะกลับเท็จในขณะที่StringComparer.InvariantCulture.Equals(a, b)จะกลับจริง
George Helyar

2

ไม่จำเป็นต้องใช้ exocles อักขระแฟนซีเพื่อแสดงความแตกต่าง ต่อไปนี้เป็นตัวอย่างง่ายๆที่ฉันพบในวันนี้ซึ่งน่าประหลาดใจประกอบด้วยอักขระ ASCII เท่านั้น

ตามตาราง ASCII 0(0x48) มีขนาดเล็กกว่า_(0x95) เมื่อเปรียบเทียบตามปกติ InvariantCulture จะพูดตรงกันข้าม (รหัส PowerShell ด้านล่าง):

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1

-7

พยายามใช้ InvariantCulture ในเมธอดสตริงที่ยอมรับว่าเป็นโอเวอร์โหลดเสมอ โดยใช้ InvariantCulture คุณจะปลอดภัย โปรแกรมเมอร์. NET จำนวนมากอาจไม่ใช้ฟังก์ชันนี้ แต่หากซอฟต์แวร์ของคุณจะถูกใช้งานในหลายวัฒนธรรม InvariantCulture นั้นเป็นคุณสมบัติที่มีประโยชน์อย่างยิ่ง


3
หากซอฟต์แวร์ของคุณจะไม่ถูกใช้งานในวัฒนธรรมที่แตกต่างกันจะช้ากว่าปกติมาก
Kyle

4
ฉันพิจารณาการ downvoting เพราะคุณไม่ได้คิดผ่านการตอบสนองแบบจับจดของคุณ แม้ว่าภายในจะเป็นเมล็ดพืชแห่งความจริง หากใบสมัครของคุณกระจายไปทั่วหลายวัฒนธรรม ... นั่นไม่รับประกันคำเปิดของคุณว่า "พยายามใช้ InvariantCulture เสมอ" ใช่ไหม? ฉันประหลาดใจที่คุณไม่ได้กลับมาหลายปีเพื่อแก้ไขความบ้าคลั่งนี้หลังจากได้รับการลงคะแนนและอาจมีประสบการณ์มากกว่านี้
Suamere
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.