IT story

someString.IndexOf (someString)은 .NET 4에서 0 대신 1을 반환합니다.

hot-time 2020. 12. 31. 22:55
반응형

someString.IndexOf (someString)은 .NET 4에서 0 대신 1을 반환합니다.


최근에 모든 프로젝트를 .NET 3.5에서 .NET 4로 업그레이드했습니다. .NET과 관련하여 다소 이상한 문제가 발생했습니다 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에서는 발생합니다.

  • IndexOf()서수 비교를 수행하도록를 변경하면 문제가 해결되므로 어떤 이유로 첫 번째 문자가 기본값으로 무시됩니다 IndexOf.

왜 이런 일이 일어나는지 아는 사람이 있습니까?

편집하다

죄송합니다. 원본 게시물에 약간의 내용을 추가하고 숨겨진 대시를 두 번 넣었습니다. 문자열을 업데이트했습니다. 올바른 편집기에 붙여 넣는 한 2 대신 1의 인덱스를 반환해야합니다.

최신 정보:

원래 문제 문자열을 모든 실제 문자가 명확하게 표시되는 문자열로 변경했습니다 (이스케이프 사용). 이것은 질문을 약간 단순화합니다.


문자열은 소프트 하이픈 (유니 코드 코드 포인트 173)과 하이픈 (유니 코드 코드 포인트 45) 의 두 문자로 존재합니다 .

Wiki : 유니 코드 표준에 따라 해당 지점에서 줄이 끊어지지 않으면 소프트 하이픈이 표시되지 않습니다.

"\xAD\x2D".IndexOf("\xAD\x2D").NET 4에서 사용할 때 소프트 하이픈을 찾고 있다는 것을 무시하고 시작 색인 1 (의 색인 \x2D)을 반환합니다 . .NET 3.5에서는 0을 반환합니다.

이 코드를 실행하면 더 재미있어집니다 ( 소프트 하이픈 찾을 ).

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

다음 i1에 관계없이 사용되는 .NET 버전의 0이된다. 의 결과 text.IndexOf(text);는 실제로 다양하며 한 눈에보기에는 버그처럼 보입니다.

프레임 워크를 통해 다시 추적 할 수있는 한 이전 .NET 버전은 InternalCall to IndexOfString()(어떤 API 호출로 연결되는지 알 수 없음)를 사용하는 반면, .NET 4에서는 QCall to InternalFindNLSStringEx()가 만들어지고 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합니다. 발견 된 문자열의 길이를 나타내는 out 매개 변수는 첫 번째 호출 이후에는 0이고 두 번째 호출 이후에는 1입니다. 소프트 하이픈은 길이가 0 인 것으로 간주됩니다.

해결 방법은 text.IndexOf(text, StringComparison.OrdinalIgnoreCase);언급했듯이을 사용하는 것입니다. 그러면 두 경우 모두 0을 반환 하는를 InternalCompareStringOrdinalIgnoreCase()차례로 호출 하는 QCall이 생성됩니다 FindStringOrdinal().


It seems be a bug in .NET4, and new changes reverted in .NET4 Beta1 to previous version same as .NET 2.0/3.0/3.5.

What's New in the BCL in .NET 4.0 CTP (MSDN blogs):

String Security Changes in .NET 4

The default partial matching overloads on System.String (StartsWith, EndsWith, IndexOf, and LastIndexOf) have been changed to be culture-agnostic (ordinal) by default.

This change affected the behavior of the String.IndexOf method by changing them to perform an ordinal (byte-for-byte) comparison by default an will be changed to use CultureInfo.InvariantCulture instead of CultureInfo.CurrentCulture.

UPDATE for .NET 4 Beta 1

In order to maintain high compatibility between .NET 4 and previous releases, we have decided to revert this change. The behavior of String's default partial matching overloads and String and Char's ToUpper and ToLower methods now behave the same as they did in .NET 2.0/3.0/3.5. The change back to the original behavior is present in .NET 4 Beta 1.


To fix this, change the string comparison method to an overload that accepts the System.StringComparison enumeration as a parameter, and specify either Ordinal or 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); 

From the documentation (my emphasis):

This method performs a word (case-sensitive and culture-sensitive) search using the current culture.

Ie. some distinct code-points will be treated as equal.

What happens if you use an overload that takes a StringComparison value and pass StringComparison.Ordinal to avoid the cultural dependencies?

ReferenceURL : https://stackoverflow.com/questions/11467424/somestring-indexofsomestring-returns-1-instead-of-0-under-net-4

반응형