好的,如果您需要用C语言进行编程,请提供具体的问题或任务,我会尽力帮助您解答或编写相应的代码。

摘要:前言 什么?用 C# 插值字符串处理器写一个输入用的 sscanf?你确定不是输出用的 sprintf? 我猜不少读者看到标题后大概会有上述的想法。然而我们这里还真就是实现 sscanf,而不是 sprintf。 插值字符串处理器 C# 有
前言 什么?用 C# 插值字符串处理器写一个输入用的 sscanf?你确定不是输出用的 sprintf? 我猜不少读者看到标题后大概会有上述的想法。然而我们这里还真就是实现 sscanf,而不是 sprintf。 插值字符串处理器 C# 有一个特性叫做插值字符串,使用插值字符串,你可以自然地往字符串里面插入变量的值,比如:$"abc{x}def",这一改以往通过 string.Format 来格式化字符串的方式,使得不再需要先传递一个字符串模板再挨个传递参数,非常方便。 在插值字符串的基础上更进一步,C# 支持插值字符串处理器,意味着你可以自定义字符串的插值行为。比如一个简单的例子: [InterpolatedStringHandler] struct Handler(int literalLength, int formattedCount) { public void AppendLiteral(string s) { Console.WriteLine($"Literal: '{s}'"); } public void AppendFormatted<T>(T v) { Console.WriteLine($"Value: '{v}'"); } } 在使用的时候,只需要把传递 string 参数的地方都换成这个 Handler 类型,就能做到按照你自定义的方式来处理插值字符串,我们的插值字符串会被 C# 编译器自动变换成 Handler 的构造和调用然后被传入: void Foo(Handler handler) { } var x = 42; Foo($"abc{x}def"); 比如上面这个例子,你会得到输出: Literal: 'abc' Value: '42' Literal: 'def' 这大大方便了各种结构化日志框架的处理,你只需要简单的把插值字符串传递进去,日志框架就能根据你插值的方式来做到结构化解析,从而完全避免了手动去格式化字符串。 带参数的插值字符串处理器 其实 C# 的插值字符串处理器还支持带额外的参数: [InterpolatedStringHandler] struct Handler(int literalLength, int formattedCount, int value) { public void AppendLiteral(string s) { Console.WriteLine($"Literal: '{s}'"); } public void AppendFormatted<T>(T v) { Console.WriteLine($"Value: '{v}'"); } } void Foo(int value, [InterpolatedStringHandlerArgument("value")] Handler handler) { } Foo(42, $"abc{x}def"); 这么一来,42 就会被传入 handler 的 value 参数当中,这允许我们捕获来自调用方的上下文,毕竟在日志场景中,根据不同参数来决定不同的格式很常见。 sscanf? 众所周知 C/C++ 里面有一个很常用的函数 sscanf,它接受一个文本输入和一个格式化模板,然后再传递对格式化部分的变量的引用,就能把变量的值解析出来: const char* input = "test 123 test"; const char* template = "test %d test"; int v = 0; sscanf(input, template, &v); printf("%d\n", v); // 123 那我们能不能在 C# 里复刻一个呢?当然可以!只不过需要一点点黑魔法。
阅读全文