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版本使用的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();
Run Code Online (Sandbox Code Playgroud)
打印0然后1.注意,length表示找到的字符串长度的out参数在第一次调用后为0,在第二次调用后为1; 软连字符被计为长度为0.
text.IndexOf(text, StringComparison.OrdinalIgnoreCase);正如您所指出的那样,解决方法是使用.这使得QCall InternalCompareStringOrdinalIgnoreCase()依次调用FindStringOrdinal(),对于两种情况都返回0.
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枚举作为参数的重载,并指定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);
Run Code Online (Sandbox Code Playgroud)