string - الاختلافات في سلسلة مقارنة طرق في C#




comparison (11)

مقارنة السلسلة في C # بسيطة جدا. في الواقع هناك العديد من الطرق للقيام بذلك. لقد أدرجت بعض في الكتلة أدناه. ما يثير فضولنا هو الاختلافات بينهم وبين متى يجب استخدام أحدهما على الآخرين؟ هل يجب تجنب أحد بأي ثمن؟ هل هناك المزيد لم أدرجه؟

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(ملاحظة: أنا أبحث عن المساواة في هذا المثال ، ليس أقل من أو أكبر من ولكن لا تتردد في التعليق على ذلك أيضًا)


Answers

يمكن العثور على شرح جيد وممارسات حول مشكلات مقارنة السلسلة في المقالة توصيات جديدة لاستخدام سلاسل في Microsoft .NET 2.0 وكذلك في أفضل الممارسات لاستخدام سلاسل في .NET Framework .

كل من الأسلوب المذكور (وغيرها) له غرض معين. الفرق الرئيسي بينهما هو نوع التعداد StringComparison الذي يستخدمه بشكل افتراضي. هناك عدة خيارات:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • ترتيبي
  • OrdinalIgnoreCase

كل نوع من أنواع المقارنة المذكورة أعلاه يستهدف حالة استخدام مختلفة:

  • ترتيبي
    • معرفات داخلية حساسة لحالة الأحرف
    • معرفات حساسة لحالة الأحرف في معايير مثل XML و HTTP
    • إعدادات الأمان الحساسة لحالة الأحرف
  • OrdinalIgnoreCase
    • معرفات داخلية غير حساسة لحالة الأحرف
    • معرفات حساسة لحالة الأحرف في معايير مثل XML و HTTP
    • مسارات الملفات (في Microsoft Windows)
    • مفاتيح التسجيل / القيم
    • متغيرات البيئة
    • معرفات الموارد (أسماء المقابض ، على سبيل المثال)
    • إعدادات الأمان غير الحساسة لحالة الأحرف
  • InvariantCulture أو InvariantCultureIgnoreCase
    • بعض استمرت البيانات ذات الصلة لغويا
    • عرض البيانات اللغوية التي تتطلب ترتيبًا ثابتًا
  • CurrentCulture أو CurrentCultureIgnoreCase
    • البيانات المعروضة للمستخدم
    • معظم مدخلات المستخدم

لاحظ أن تعداد StringComparison وكذلك الأحمال الزائدة لطرق مقارنة السلسلة موجود منذ .NET 2.0.

String.CompareTo Method (String)

هو في الواقع نوع تنفيذ آمن من IComparable.CompareTo الأسلوب . التفسير الافتراضي: CurrentCulture.

الاستعمال:

تم تصميم طريقة CompareTo في المقام الأول للاستخدام في عمليات الفرز أو الترتيب الأبجدي

وهكذا

تنفيذ واجهة IComparable سيستخدم بالضرورة هذه الطريقة

طريقة String.Compare

عضو ثابت في فئة String والذي يحتوي على الكثير من الأحمال الزائدة. التفسير الافتراضي: CurrentCulture.

كلما كان ذلك ممكناً ، يجب استدعاء الحمل الزائد من طريقة مقارنة يتضمن معلمة StringComparison.

طريقة String.Equals

تجاوز من فئة كائن وتغاضى عن سلامة نوع. التفسير الافتراضي: ترتيبي. لاحظ أن:

تتضمن أساليب المساواة في فئة السلسلة الأكوام الساكنة والمشغل الثابت == وأسلوب المثالية يساوي .

فئة StringComparer

هناك أيضًا طريقة أخرى للتعامل مع مقارنات السلاسل خاصةً تهدف إلى الفرز:

يمكنك استخدام الفئة StringComparer لإنشاء مقارنة خاصة بكل نوع لفرز العناصر في مجموعة عامة. تستخدم فئات مثل Hashtable و Dictionary و SortedList و SortedList الفئة StringComparer لأغراض الفرز.


كما قال Ed ، يتم استخدام CompareTo للفرز.

هناك اختلاف ، ومع ذلك ، بين .Equals و ==.

== يقرر إلى الكود التالي:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

السبب البسيط هو التالي سوف يرمي استثناء:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

والخطوات التالية لن:

string a = null;
string b = "foo";

bool equal = a == b;

فيما يلي القواعد الخاصة بكيفية عمل هذه الوظائف:

stringValue.CompareTo(otherStringValue)

  1. null يأتي قبل سلسلة
  2. ويستخدم CultureInfo.CurrentCulture.CompareInfo.Compare ، مما يعني أنه سيستخدم مقارنة تعتمد على البيانات. قد يعني هذا أن ß ستقارن بـ SS في ألمانيا ، أو ما شابه

stringValue.Equals(otherStringValue)

  1. لا تعتبر null مساوية لأي شيء
  2. إلا إذا قمت بتحديد خيار StringComparison ، فسوف يستخدم ما يشبه فحصًا للمساواة الترتيبية المباشرة ، بمعنى أن ß ليس هو نفسه SS ، بأي لغة أو ثقافة

stringValue == otherStringValue

  1. ليس هو نفسه stringValue.Equals() .
  2. يقوم عامل التشغيل == باستدعاء القيمة الساكنة Equals(string a, string b) (والتي بدورها تذهب إلى EqualsHelper الداخلي EqualsHelper المقارنة.
  3. استدعاء .Equals() على سلسلة null تحصل على استثناء مرجع null ، في حين أن == لا.

Object.ReferenceEquals(stringValue, otherStringValue)

فقط يتحقق من أن المراجع هي نفسها ، بمعنى أنها ليست مجرد سلسلتين لها نفس المحتويات ، فأنت تقارن كائن سلسلة بنفسها.

لاحظ أنه مع وجود الخيارات الموجودة أعلاه التي تستخدم مكالمات الأسلوب ، توجد زيادة في التحميل تحتوي على المزيد من الخيارات لتحديد كيفية المقارنة.

نصيحتي إذا كنت ترغب فقط في التحقق من المساواة هو أن .CompareTo ما إذا كنت تريد استخدام مقارنة تعتمد على ثقافة أم لا ، ومن ثم استخدم .CompareTo أو .Equals ، اعتمادا على الاختيار.


في النماذج التي ذكرتها هنا ، لا يوجد فرق كبير بين الاثنين. ينتهي CompareTo باستدعاء طريقة CompareInfo التي تقوم بإجراء مقارنة باستخدام الثقافة الحالية ؛ يسمى Equals قبل == المشغل.

إذا كنت تفكر في الحمل الزائد ، فستصبح الأمور مختلفة. Compare و == يمكن فقط استخدام الثقافة الحالية لمقارنة سلسلة. يمكن أن Equals و StringComparison حجة تعداد StringComparison التي تتيح لك تحديد مقارنات حساسة للثقافة أو غير حساسة لحالة الأحرف. فقط String.Compare يسمح لك بتحديد CultureInfo وإجراء مقارنات باستخدام ثقافة أخرى غير الثقافة الافتراضية.

بسبب تنوعها ، أجد أنني أستخدم String.Compare أكثر من أي طريقة مقارنة أخرى. يتيح لي تحديد ما أريده بالضبط.


من MSDN:

"تم تصميم الأسلوب CompareTo بشكل أساسي للاستخدام في عمليات الفرز أو الترتيب الأبجدي. يجب عدم استخدامه عندما يكون الغرض الأساسي من استدعاء الأسلوب هو تحديد ما إذا كانت سلسلتين متكافئتين. لتحديد ما إذا كانت سلسلتين متكافئتين ، قم باستدعاء طريقة Equals. "

يقترحون استخدام .Equals بدلاً من .CompareTo عندما تبحث فقط عن المساواة. لست متأكدا إذا كان هناك فرق بين .Equals و == لفئة string . .Equals أحيانًا .Equals أو Object.ReferenceEquals بدلاً من == Object.ReferenceEquals الخاصة في حالة حضور أحدهم في وقت لاحق وإعادة تعريف عامل == لهذه الفئة.


يقارن CompareTo السلسلة مع كائن سلسلة وإرجاع قيمة int. إذا كانت القيمة 0 ، فهذا يعني أن السلاسل متساوية.

string country = "southindia";
object ob1 = country.Clone();
Console.WriteLine( country.CompareTo(ob1));

string country = "southindia";
string cou = "insia";
int n = country.CompareTo(cou);
Console.WriteLine( n );

إذا كنت تشعر بالفضول حول الاختلافات في أساليب BCL ، Reflector هو صديقك :-)

أتبع هذه الإرشادات:

المطابقة التامة: EDIT: لقد استخدمت دائمًا == عامل التشغيل على مبدأ أنه داخل Equals (string ، string) يتم استخدام الكائن object = = لمقارنة مراجع الكائن ولكن يبدو أن strA.Equals (strB) لا يزال 1-11٪ أسرع عموما من string.Equals (strA ، strB) ، strA == strB ، و string.CompareOrdinal (strA ، strB). أنا حلقة اختبار مع StopWatch على كل من القيم سلسلة interned / غير interned ، مع أطوال سلسلة نفس / مختلفة ، وأحجام مختلفة (1B إلى 5MB).

strA.Equals(strB)

مباراة سهلة القراءة (الثقافات الغربية ، غير حساسة لحالة الأحرف):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

مباراة سهلة القراءة (جميع الثقافات الأخرى ، حالة غير حساسة / اللهجة / kana / الخ التي حددتها CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

تطابق قابل للقراءة مع القواعد المخصصة (جميع الثقافات الأخرى):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0

مع .EQUALS ، يمكنك أيضا الحصول على خيارات StringComparison. سهل جدا لتجاهل القضية وغيرها من الأشياء.

راجع للشغل ، وهذا سوف يقيّم كاذبة

string a = "myString";
string b = "myString";

return a==b

بما أن = = يقارن قيم a و b (وهي مؤشرات) ، فسيتم تقييم هذا فقط إلى true إذا كانت المؤشرات تشير إلى نفس الكائن في الذاكرة. .Equals dereferences المؤشرات ويقارن القيم المخزنة في المؤشرات. a.Equals (ب) سيكون صحيحا هنا.

وإذا قمت بتغيير b إلى:

b = "MYSTRING";

ثم a.Equals (ب) غير صحيح ، ولكن

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

سيكون صحيحا

a.CompareTo (b) يستدعي الدالة CompareTo الخاصة بالسلسلة التي تقارن القيم في المؤشرات وتعيد <0 إذا كانت القيمة المخزنة في a أقل من القيمة المخزنة عند b ، تُرجع 0 إذا كانت a.Equals (b) صحيحة ، و > 0 خلاف ذلك. ومع ذلك ، فهذا أمر حساس لحالة الأحرف ، وأعتقد أن هناك خيارات محتملة لـ CompareTo لتجاهل الحالة ومثل هذه الحالة ، ولكن ليس لدينا وقت للنظر الآن. وكما ذكر آخرون بالفعل ، فسيتم القيام بذلك من أجل الفرز. المقارنة من أجل المساواة بهذه الطريقة يؤدي إلى نفقات غير ضرورية.

أنا متأكد من مغادرتي للأشياء ، ولكن أعتقد أن هذا يجب أن يكون معلومات كافية لبدء التجريب إذا كنت بحاجة إلى مزيد من التفاصيل.


لا يعني ذلك أن الأداء عادة ما يكون مهمًا بنسبة 99٪ من المرات التي تحتاج فيها إلى ذلك ، ولكن إذا كان عليك القيام بذلك في حلقة عدة ملايين المرات ، فإنني أقترح عليك بشدة أن تستخدم .Equals أو == لأنه بمجرد العثور على شخصية التي لا تتطابق مع أنه يرمي كل شيء على أنه خطأ ، ولكن إذا استخدمت CompareTo ، فسيكون عليك معرفة أي حرف أقل من الآخر ، مما يؤدي إلى وقت أداء أسوأ قليلاً.

إذا كان تطبيقك سيعمل في بلدان مختلفة ، فإنني أوصيك بأن تلقي نظرة على آثار CultureInfo وربما تستخدم .Equals. نظرًا لأنني لا أكتب إلا التطبيقات للولايات المتحدة (ولا يهمني ما إذا كانت لا تعمل بشكل صحيح من قِبل شخص ما) ، فأنا أستخدم دائمًا == فقط.


  • s1.CompareTo (s2): لا تستخدم إذا كان الهدف الأساسي هو تحديد ما إذا كانت سطرين متساويين
  • s1 == s2: لا يمكن تجاهل الحالة
  • s1.Equals (s2، StringComparison): Throws NullReferenceException إذا كانت s1 خالية
  • String.Equals (s2، StringComparison): بواسطة عملية eliminiation، هذه الطريقة الثابتة هي WINNER (بافتراض حالة استخدام نموذجية لتحديد ما إذا كانت سطرين مكافئتين)!

It depends on what you want the bytes FOR

This is because, as Tyler so aptly said , "Strings aren't pure data. They also have information ." In this case, the information is an encoding that was assumed when the string was created.

Assuming that you have binary data (rather than text) stored in a string

This is based off of OP's comment on his own question, and is the correct question if I understand OP's hints at the use-case.

Storing binary data in strings is probably the wrong approach because of the assumed encoding mentioned above! Whatever program or library stored that binary data in a string (instead of a byte[] array which would have been more appropriate) has already lost the battle before it has begun. If they are sending the bytes to you in a REST request/response or anything that must transmit strings, Base64 would be the right approach.

If you have a text string with an unknown encoding

Everybody else answered this incorrect question incorrectly.

If the string looks good as-is, just pick an encoding (preferably one starting with UTF), use the corresponding System.Text.Encoding.???.GetBytes() function, and tell whoever you give the bytes to which encoding you picked.





c# string comparison