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

2019-06-26 06:47发布

我们最近升级了我们的所有项目从.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,只要你把它粘贴到正确的编辑器。

更新:

改变了原来的问题串一个,每一个字符是清晰可见(使用转义)。 这简化了问题了一下。

Answer 1:

您的字符串存在的两个角色:一个连字符 (Unicode代码点173)和连字符 (Unicode代码点45)。

维基 :根据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);

然后i1变为0,而不管所使用的.NET版本。 的结果text.IndexOf(text); 的确变化,这一眼看起来像我的错误。

至于我可以跟踪回通过框架,旧的.NET版本使用的InternalCall到IndexOfString()我想不出哪个API调用云),而.NET 4 QCall到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 ,指示所找到的字符串的长度的输出参数,为0之后的第二,第一呼叫和1之后; 软连字符被计数为具有0的长度。

解决方法是使用text.IndexOf(text, StringComparison.OrdinalIgnoreCase); ,因为你已经注意到。 这使得QCall到InternalCompareStringOrdinalIgnoreCase()后者又调用FindStringOrdinal()这两种情况下返回0。



Answer 2:

这似乎是在.NET4 Beta1中恢复到以前的版本相同的.NET 2.0 / 3.0 / 3.5.NET4中的错误,以及新的变化。

什么是新的BCL在.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和之前版本之间兼容性高,我们决定恢复这一变化。 字符串的默认部分匹配的重载和字符串和字符的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); 


Answer 3:

从文档 (我的重点):

此方法执行字( 区分大小写和文化敏感 )使用当前区域性搜索。

IE浏览器。 一些明显的码点将被视为相等。

如果您使用过载,需要一个会发生什么StringComparison值,并通过StringComparison.Ordinal避免文化的依赖?



文章来源: someString.IndexOf(someString) returns 1 instead of 0 under .NET 4