c# - someString.IndexOf(someString).NET 4 के तहत 0 के बजाय 1 देता है




.net-4.0 .net-3.5 (4)

हमने हाल ही में हमारी सभी परियोजनाओं को .NET 3.5 से .NET 4 तक अपग्रेड कर दिया है। मैं string.IndexOf() संबंध में एक अजीब समस्या में आया हूं।

मेरा कोड स्पष्ट रूप से कुछ अलग करता है, लेकिन इस मुद्दे की जांच की प्रक्रिया में, मैंने पाया कि एक स्ट्रिंग पर IndexOf() को कॉल करने के साथ ही 0 के बजाय 1 लौटा दिया गया है। दूसरे शब्दों में:

string text = "\xAD\x2D";          // problem happens with "­-dely N.China", too;
int index = text.IndexOf(text);    // see update note below.

मुझे 0 की बजाय 1 की अनुक्रमणिका दें। इस समस्या के बारे में कुछ बातें ध्यान दें:

  • समस्याएं इन हाइफ़न से संबंधित होती हैं (पहला चरित्र यूनिकोड नरम हाइफ़न है, दूसरा नियमित हाइफ़न है)।

  • मैंने दो बार चेक किया है, यह .NET 3.5 में नहीं होता है लेकिन .NET 4 में होता है।

  • एक ordinal तुलना करने के लिए IndexOf() को बदलने से समस्या ठीक होती है, इसलिए किसी कारण से कि डिफ़ॉल्ट वर्ण डिफ़ॉल्ट IndexOf साथ अनदेखा किया जाता है।

क्या किसी को पता है यह क्यों होता है?

संपादित करें

क्षमा करें दोस्तों ने मूल पोस्ट पर सामान का थोड़ा सा हिस्सा बनाया और वहां दो बार छुपा डैश मिला। मैंने स्ट्रिंग को अद्यतन किया है, इसे 2 के बजाय 1 की अनुक्रमणिका वापस करनी चाहिए, जब तक कि आप इसे सही संपादक में पेस्ट करें।

अद्यतन करें:

मूल समस्या स्ट्रिंग को उस स्थान पर बदल दिया जहां प्रत्येक वास्तविक वर्ण स्पष्ट रूप से दिखाई देता है (भागने का उपयोग करके)। यह सवाल थोड़ा सा सरल बनाता है।


Answers

आपकी स्ट्रिंग दो अक्षरों में मौजूद है: एक नरम हाइफ़न (यूनिकोड कोड बिंदु 173) और एक hyphen (यूनिकोड कोड बिंदु 45)।

Wiki : यूनिकोड मानक के अनुसार, उस बिंदु पर लाइन टूटा नहीं जाता है, तो एक नरम हाइफ़न प्रदर्शित नहीं होता है।

.NET 4 में "\xAD\x2D".IndexOf("\xAD\x2D") का उपयोग करते समय, ऐसा लगता है कि आप नरम हाइफ़न की तलाश में हैं, 1 की प्रारंभिक अनुक्रमणिका ( \x2D की अनुक्रमणिका) \x2D । .NET 3.5 में, यह 0 देता है।

अधिक मजेदार, यदि आप इस कोड को चलाते हैं (इसलिए जब केवल नरम हाइफ़न की तलाश होती है):

string text = "\xAD\x2D";
string shy = "\xAD";
int i1 = text.IndexOf(shy);

तो i1 जाता है, भले ही .NET संस्करण का उपयोग किया जाता है। text.IndexOf(text); का परिणाम। text.IndexOf(text); वास्तव में भिन्न होता है, जो एक नज़र में मुझे एक बग की तरह दिखता है।

जहां तक ​​मैं ढांचे के माध्यम से वापस ट्रैक कर सकता हूं, पुराने .NET संस्करण IndexOfString() एक InternalCall IndexOfString() उपयोग करते हैं (मुझे पता नहीं है कि कौन सी एपीआई कॉल जाता है), जबकि .NET 4 से QCall से InternalFindNLSStringEx() को बनाया जाता है , जो बदले में FindNLSStringEx() कॉल FindNLSStringEx()

मुद्दा (मैं वास्तव में यह नहीं समझ सकता कि यह इरादा व्यवहार है) वास्तव में FindNLSStringEx कॉल करते समय होता है:

LPCWSTR lpStringSource = L"\xAD\x2D";
LPCWSTR lpStringValue = L"\xAD";

int length;

int i = FindNLSStringEx(
    LOCALE_NAME_SYSTEM_DEFAULT,
    FIND_FROMSTART,
    lpStringSource,
    -1,
    lpStringValue,
    -1,
    &length,
    NULL,
    NULL,
    1);

Console::WriteLine(i);

i = FindNLSStringEx(
    LOCALE_NAME_SYSTEM_DEFAULT,
    FIND_FROMSTART,
    lpStringSource,
    -1,
    lpStringSource,
    -1,
    &length,
    NULL,
    NULL,
    1);

Console::WriteLine(i);

Console::ReadLine();

प्रिंट 0 और उसके बाद 1. ध्यान दें कि length , पाया गया स्ट्रिंग की लंबाई इंगित करने वाला एक पैरामीटर, पहले कॉल के बाद 0 और दूसरे के बाद 1 है; नरम हाइफ़न को 0 की लंबाई के रूप में गिना जाता है।

वर्कअराउंड text.IndexOf(text, StringComparison.OrdinalIgnoreCase); का उपयोग करना है। text.IndexOf(text, StringComparison.OrdinalIgnoreCase); जैसा कि आपने नोट किया है। यह InternalCompareStringOrdinalIgnoreCase() QCall बनाता है जो बदले में FindStringOrdinal() कॉल FindStringOrdinal() , जो दोनों मामलों के लिए 0 देता है।


ऐसा लगता है कि .NET4 में एक बग है, और .NET4 बीटा 1 में नए संस्करणों को पिछले संस्करण में .NET 2.0 / 3.0 / 3.5 के रूप में वापस लाया गया है।

बीसीएल में .NET 4.0 सीटीपी (एमएसडीएन ब्लॉग) में नया क्या है :

स्ट्रिंग सुरक्षा .NET 4 में परिवर्तन

System.String (StartsWith, EndsWith, IndexOf, और LastIndexOf) पर डिफ़ॉल्ट आंशिक मिलान ओवरलोड को डिफ़ॉल्ट रूप से संस्कृति-अज्ञेय (ordinal) के रूप में बदल दिया गया है।

इस परिवर्तन ने String.IndexOf विधि के व्यवहार को डिफ़ॉल्ट रूप से एक औपचारिक (बाइट-फॉर-बाइट) तुलना करने के लिए बदलकर बदल दिया है, जिसे CultureInfo.InvariantCulture बजाय CultureInfo.InvariantCulture का उपयोग करने के लिए बदला जाएगा।

.NET 4 बीटा 1 के लिए अद्यतन करें

.NET 4 और पिछले रिलीज़ के बीच उच्च संगतता बनाए रखने के लिए, हमने इस परिवर्तन को वापस करने का निर्णय लिया है। स्ट्रिंग के डिफ़ॉल्ट आंशिक मिलान ओवरलोड और स्ट्रिंग और चार के ToUpper और ToLower विधियों का व्यवहार अब वही व्यवहार करता है जैसा उन्होंने .NET 2.0 / 3.0 / 3.5 में किया था। मूल व्यवहार में परिवर्तन .NET 4 बीटा 1 में मौजूद है।

इसे ठीक करने के लिए , स्ट्रिंग तुलना विधि को ओवरलोड पर बदलें जो सिस्टम को स्वीकार करता है। स्ट्रिंग OrdinalIgnoreCase गणना पैरामीटर के रूप में, और या तो OrdinalIgnoreCase या OrdinalIgnoreCase निर्दिष्ट करें।

// string contains 'unicode dash' \x2D
string text = "\xAD\x2D"; 

// woks in .NET 2.0/3.0/3.5 and .NET 4 Beta 1 and later
// but seems be buggy in .NET 4 because of 'culture-sensitive' comparison        
int index = text.IndexOf(text); 

// fixed version
index = text.IndexOf(text, StringComparison.Ordinal); 

documentation (मेरा जोर):

यह विधि वर्तमान संस्कृति का उपयोग करके एक शब्द ( केस-संवेदनशील और संस्कृति-संवेदनशील ) खोज करता है।

अर्थात। कुछ विशिष्ट कोड-पॉइंट बराबर माना जाएगा।

क्या होता है यदि आप एक अधिभार का उपयोग करते हैं जो StringComparison मान लेता है और सांस्कृतिक निर्भरताओं से बचने के लिए StringComparison.Ordinal पास करता है?


वास्तव में बहुत आसान है।

VB.NET:

Private Function SplitOnNewLine(input as String) As String
    Return input.Split(Environment.NewLine)
End Function

सी#:

string splitOnNewLine(string input)
{
    return input.split(environment.newline);
}




c# string .net-4.0 .net-3.5