我们最近升级了我们的所有项目从.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,只要你把它粘贴到正确的编辑器。
更新:
改变了原来的问题串一个,每一个字符是清晰可见(使用转义)。 这简化了问题了一下。
您的字符串存在的两个角色:一个连字符 (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。
这似乎是在.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
枚举作为参数,并指定Ordinal
或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);
从文档 (我的重点):
此方法执行字( 区分大小写和文化敏感 )使用当前区域性搜索。
IE浏览器。 一些明显的码点将被视为相等。
如果您使用过载,需要一个会发生什么StringComparison
值,并通过StringComparison.Ordinal
避免文化的依赖?