先想想看,你以为底下代码复返值是几许?
"hello".IndexOf("", 2);
"hello".IndexOf("\0", 2);
"hello".IndexOf('\0', 2)
今天和大家共享对于.net core中与字符相干的一些奇怪问题。
领先咱们先以.NET8规划框架作念为测试环境。顺利上代码:
using System.Reflection;
using System.Runtime.Versioning;
namespace TestNetCore
{
internal class Program
{
static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly();
var targetFramework = (TargetFrameworkAttribute?)Attribute.GetCustomAttribute(assembly, typeof(TargetFrameworkAttribute));
if (targetFramework != null)
{
Console.WriteLine($"规划框架: {targetFramework.FrameworkName}");
}
Console.WriteLine(@"""hello"".IndexOf("""", 2) 放荡:" + "hello".IndexOf("", 2));
Console.WriteLine(@"""hello"".IndexOf(""\0"", 2) 放荡:" + "hello".IndexOf("\0", 2));
Console.WriteLine(@"""hello"".IndexOf('\0', 2) 放荡:" + "hello".IndexOf('\0', 2));
Console.ReadKey();
}
}
}
运行放荡如下:
这与你设计的放荡有隔离吗?天然仅仅一个花式,三行代码,可是这里面包含了许多学问点,底下咱们就来具体聊聊为什么是这么的放荡,底层逻辑是什么。
笃信大多量东谈主会有以下几个疑问:
为什么查找空字符串复返2为什么查找“\0”也复返2为什么查找‘\0‘又复返-1
底下咱们一个一个来说,领先来说为什么"hello".IndexOf("", 2)复返2,这个问题比拟通俗,等于花式自己界说问题,不错稽查官方文档有详备确认,如下图:
花式界说如斯,淌若查询的值为空字符串,则复返值为startIndex,即查找肇始位置索引,因为"hello".IndexOf("", 2)的2暗示从索引2处开动查找,是以此这行代码复返2。
天然这里仅仅通俗地把空字符串改成了“\0”,可是里的问题就比拟复杂了,波及到多个学问点,领先这里波及到Unicode编码问题,面前文化修复问题,以及.NET全球化问题。
咱们先回到这个问题,先来望望官方文档确认,如下图:
从这里面不错斗胆预计“\0”等于属于可忽略字符,况兼淌若查询的字符串包含了可忽略字符,则放荡和移除该字符搜索等效,那么"hello".IndexOf("\0", 2)就等效与"hello".IndexOf("", 2),因此复返2也就顺利成章了。
领先咱们预计是正确的,“\0确切属于可忽略字符,这等于Unicode编码次序问题,而且不只单“\0“会有这么的问题,Unicdoe可忽略字符齐会有这么的问题,比如”“、”“等。
Console.WriteLine(@"""hello"".IndexOf("""", 2) 放荡:" + "hello".IndexOf("", 2));
Console.WriteLine(@"""hello"".IndexOf("""", 2) 放荡:" + "hello".IndexOf("", 2));
本质着力如下
这个谜底在上头的官方文档确认中也不错看到蛛丝马迹,“在本质话语性的或分袂区域性的比拟时该字符不被计划“,这句话是要道,确认IndexOf花式是会受面前文化修复影响的,天然咱们写的代码里莫得看到相干面前文化修复,可是不代表莫得,咱们不错看下IndexOf相干的重载花式。
红框中StringComparison参数就不错修复面前文化。咱们望望有哪些修复选项。
因为"hello".IndexOf("\0", 2)里面使用了StringComparison.CurrentCulture 而"hello".IndexOf(‘\0’, 2) 里面使用了StringComparison.Ordinal,等于因为CurrentCulture陈设值导致“在本质话语性的或分袂区域性的比拟时”\0“不被计划“,被顺利忽略了,而Ordinal陈设值不会有这么的问题,是以莫得被忽略,是以"hello".IndexOf(‘\0’, 2)复返-1。
咱们也不错顺利调用IndexOf重载花式,指定StringComparison来达到咱们想要的着力。
Console.WriteLine(@"""hello"".IndexOf(""\0"", 2, 3, StringComparison.CurrentCulture) 放荡:" + "hello".IndexOf("\0", 2, 3, StringComparison.CurrentCulture));
Console.WriteLine(@"""hello"".IndexOf(""\0"", 2, 3, StringComparison.Ordinal) 放荡:" + "hello".IndexOf("\0", 2, 3, StringComparison.Ordinal));
运行代码如下:
天然原因找到了,可是咱们再深切念念考一下,为什么会有这么的相反呢?唯有IndexOf花式有这么的问题吗?
要回话这个问题,等于咱们上头提到的.NET全球化问题了。在 .NET 5 前,.NET 全球化 API 在不同的平台上使用不同的基础库。 在 Unix 上,API 使用 Unicode 海外组件 (ICU),在 Windows 上,API 使用 区域话语相沿 (NLS)。 这导致在不同平台上运走运用要领时,在少数全球化 API 中存在一些活动相反。 可是以下方面存在彰着的活动相反:区域性和区域性数据、字符串大小写、字符串排序和搜索、排序要道字、字符串次序化、海外化域名 (IDN) 相沿、Linux 上的时区知道称号。
因此不只单IndexOf花式有这么的问题,底下这些API齐有存在相同的问题:
System.String.Compare
System.String.EndsWith
System.String.IndexOf
System.String.StartsWith
System.String.ToLower
System.String.ToLowerInvariant
System.String.ToUpper
System.String.ToUpperInvariant
System.Globalization.TextInfo(大多量成员)
System.Globalization.CompareInfo(大多量成员)
System.Array.Sort(对字符串数组进行排序时)
System.Collections.Generic.List<T>.Sort()(当列表元素为字符串时)
System.Collections.Generic.SortedDictionary<TKey,TValue>(当键为字符串时)
System.Collections.Generic.SortedList<TKey,TValue>(当键为字符串时)
System.Collections.Generic.SortedSet<T>(当集包含字符串时)
这里面许多花式齐是有多个重载花式的,而每个重载花式默许面前文化修复可能并不调换。因此大家在开荒的时刻一定要审视使用,一不提神肯能就好引起一些奇怪的问题,因此大家尽量我方手动指定面前文化修复。
下表列出一些花式其对应的默许活动。
注:天然淌若调用方提供显式 CultureInfo 或 StringComparison 参数,则该参数将优先于任何默许值。
终末回归一下
IndexOf对于Empty字符查找会复返开动查找索引startIndex欧洲杯体育,而不是咱们遐想中的-1;Unicode可忽略字符受StringComparison参数影响很大,会顺利把相应字符顺利忽略掉.NET全球化进度中,在向 迁徙是势必,因此咱们在使用相干花式时一定要提神淌若不错尽量主动知道修复面前文化区域修复