someString.IndexOf(someString)在.NET 4下返回1而不是0
我们最近把我们所有的项目从.NET 3.5升级到了.NET 4.我遇到了string.IndexOf()
方面相当奇怪的问题。
我的代码显然做了一些稍微不同的事情,但在调查问题的过程中,我发现调用IndexOf()
的string本身返回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
忽略。
有谁知道为什么发生这种情况?
编辑
对不起,伙计们在原帖上写了一些东西,并在那里得到了两次隐藏的冲刺。 我已经更新了string,这应该返回索引1而不是2,只要您将其粘贴到正确的编辑器。
更新:
将原始问题string更改为每个实际字符清晰可见(使用转义)。 这简化了一些问题。
您的string存在两个字符:一个软连字符 (Unicode代码点173)和一个连字符 (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);
那么无论使用的是什么.NET版本, i1
变成0。 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.请注意,表示所findstringlength
的out参数的长度在第一次调用后为0,在第二次调用后为1。 软连字符被计为长度为0。
解决方法是使用text.IndexOf(text, StringComparison.OrdinalIgnoreCase);
,正如你所指出的那样。 这使QCall到InternalCompareStringOrdinalIgnoreCase()
,然后调用FindStringOrdinal()
,这两个情况下返回0。
这似乎是在.NET4中的一个错误,新的变化在.NET4 Beta1恢复到以前的版本相同的.NET 2.0 / 3.0 / 3.5 。
.NET 4.0 CTP中BCL的新特性 (MSDN博客) :
.NET 4中的string安全性更改
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中存在回到原始行为的变化。
要解决此问题 ,请将string比较方法更改为接受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
来避免文化依赖的重载,会发生什么?
- IQueryable <T>和IEnumerable <T>有什么区别?
- HTTP错误500.22 – 内部服务器错误(已检测到ASP.NET设置不适用于集成pipe理pipe道模式。)
- StringDictionary vs Dictionary <string,string>
- 第一次调用CanExecute时,WPF CommandParameter为NULL
- 我怎样才能在IIS7工作中获得gzip压缩?
- 用LINQ分页收集
- 查看用户是否属于C#+ Asp.net中Active Directory组的一部分
- 使用LINQ获取一个List <>中的项目,这些项目不在另一个List <>中
- 你如何确定两个哈希集是否相等(按值,而不是参考)?