someString.IndexOf(someString)在.NET 4下返回1而不是0

kne*_*sis 56 c# string .net-4.0 .net-3.5

我们最近将所有项目从.NET 3.5升级到.NET 4.我遇到了一个相当奇怪的问题string.IndexOf().

我的代码显然略有不同,但在调查问题的过程中,我发现调用IndexOf()一个字符串本身返回1而不是0.换句话说:

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

给我一个索引1而不是0.关于这个问题需要注意几点:

  • 问题似乎与这些连字符有关(第一个字符是Unicode软连字符,第二个字符是常规连字符).

  • 我已经仔细检查过,这不会发生在.NET 3.5中,而是发生在.NET 4中.

  • 更改IndexOf()要进行序数比较可以解决问题,因此出于某种原因,默认情况下会忽略第一个字符IndexOf.

有谁知道为什么会这样?

编辑

对不起,伙计们,在原帖上做了一些东西,并在那里得到了隐藏的短跑两次.我已经更新了字符串,只要将其粘贴到正确的编辑器中,就应该返回1而不是2的索引.

更新:

将原始问题字符串更改为每个实际字符清晰可见的字符串(使用转义).这有点简化了问题.

Cod*_*ter 32

您的字符串包含两个字符:软连字符(Unicode代码点173)和连字符(Unicode代码点45).

Wiki:根据Unicode标准,如果该行没有断开,则不会显示软连字符.

"\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);
Run Code Online (Sandbox Code Playgroud)

然后i1变为0,而不管所使用的.NET版本.结果text.IndexOf(text);确实不一样,一眼就看起来像是一个错误.

至于我可以跟踪回通过框架,旧的.NET版本使用的InternalCallIndexOfString()(我想不出哪个API调用云),而.NET 4 QCallInternalFindNLSStringEx()制成,这反过来又来电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();
Run Code Online (Sandbox Code Playgroud)

打印0然后1.注意,length表示找到的字符串长度的out参数在第一次调用后为0,在第二次调用后为1; 软连字符被计为长度为0.

text.IndexOf(text, StringComparison.OrdinalIgnoreCase);正如您所指出的那样,解决方法是使用.这使得QCall InternalCompareStringOrdinalIgnoreCase()依次调用FindStringOrdinal(),对于两种情况都返回0.

  • 好吧,我将把它视为非预期的行为,直到另有说明.感谢所有的努力,CodeCaster. (2认同)

Ria*_*Ria 20

它似乎是.NET4中的一个错误,并且.NET4 Beta1中的新更改恢复到与.NET 2.0/3.0/3.5相同的先前版本.

.NET 4.0 CTP(MSDN博客)中BCL的新功能:

.NET 4中的字符串安全性更改

默认情况下,System.String(StartsWith,EndsWith,IndexOf和LastIndexOf)上的默认部分匹配重载已更改为与文化无关(序号).

此更改String.IndexOf通过更改它们以执行顺序(逐字节)比较来影响方法的行为,默认情况下将更改为使用CultureInfo.InvariantCulture而不是CultureInfo.CurrentCulture.

.NET 4 Beta 1的更新

为了保持.NET 4与以前版本之间的高兼容性,我们决定恢复此更改.String的默认部分匹配重载和String和Char的ToUpper和ToLower方法的行为现在与.NET 2.0/3.0/3.5中的行为相同..NET 4 Beta 1中存在对原始行为的更改.


要解决此问题,请将字符串比较方法更改为接受System.StringComparison枚举作为参数的重载,并指定OrdinalOrdinalIgnoreCase.

// 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); 
Run Code Online (Sandbox Code Playgroud)

  • 请将您链接的帖子的简短摘要直接添加到答案中.引用一个来源总是很棒,但任何SO答案都应该带有意义,而不必遵循外部链接. (3认同)