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

时间:2012-07-13 09:08:52

标签: 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.

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

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

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

  • 更改IndexOf()以执行序数比较可解决此问题,因此出于某种原因,使用默认IndexOf忽略第一个字符。

有谁知道为什么会这样?

修改

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

更新

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

3 个答案:

答案 0 :(得分:32)

您的字符串包含两个字符:soft hyphen(Unicode代码点173)和hyphen(Unicode代码点45)。

  

Wiki:根据Unicode标准,如果该行没有被破坏,则不会显示软连字符。

在.NET 4中使用"\xAD\x2D".IndexOf("\xAD\x2D")时,似乎忽略了您正在寻找软连字符,返回起始索引为1(索引为\x2D)。在.NET 3.5中,它返回0。

更有趣的是,如果你运行这段代码(所以当寻找软连字符时):

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

然后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();

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

解决方法是使用text.IndexOf(text, StringComparison.OrdinalIgnoreCase);,正如您所指出的那样。这使QCall成为InternalCompareStringOrdinalIgnoreCase(),而{{1}}又调用FindStringOrdinal(),两种情况都返回0。

答案 1 :(得分:20)

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

  

What's New in the BCL in .NET 4.0 CTP(MSDN博客)

     

.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中存在对原始行为的更改。


To fix this,将字符串比较方法更改为接受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); 

答案 2 :(得分:0)

documentation(我的重点):

  

此方法使用当前文化执行单词( 区分大小写且对文化敏感的 )搜索。

IE中。一些不同的代码点将被视为相等。

如果您使用带有StringComparison值并传递StringComparison.Ordinal的重载以避免文化依赖性,会发生什么?