上一篇 用 HexColor 作为示例,可能过于简单

这里再补充一个 ini 解析的示例

由于实在写不动用其他库解析 ini 了, 春节都要过完了,累了,写不动了,

所以随意找了一份解析ini的库, 仅供参考,对比不准确,毕竟完整库包含了更多功能

先看看结果


BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3)
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
Method Mean Error StdDev Gen0 Gen1 Allocated
Hande_Ini 567.9 ns 11.24 ns 21.66 ns 0.2851 - 1.75 KB
RuQu_Ini 1,691.4 ns 33.48 ns 64.51 ns 0.4177 - 2.56 KB
IniDataParser 4,836.3 ns 94.44 ns 167.87 ns 1.1215 0.0076 6.91 KB
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Gen0 : GC Generation 0 collects per 1000 operations
Gen1 : GC Generation 1 collects per 1000 operations
Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
1 ns : 1 Nanosecond (0.000000001 sec)

总结

  • delegate 肯定会有调用消耗,ini 场景使用的函数远多于 HexColor ,可以看到消耗大了很多

先看来自 dotnet Microsoft.Extensions.Configuration 中解析 ini 的代码

public static IDictionary<string, string?> Read(string content)
{
var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
using (var reader = new StringReader(content))
{
string sectionPrefix = string.Empty; while (reader.Peek() != -1)
{
string rawLine = reader.ReadLine()!; // Since Peak didn't return -1, stream hasn't ended.
string line = rawLine.Trim(); // Ignore blank lines
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
// Ignore comments
if (line[0] is ';' or '#' or '/')
{
continue;
}
// [Section:header]
if (line[0] == '[' && line[line.Length - 1] == ']')
{
// remove the brackets
sectionPrefix = string.Concat(line.AsSpan(1, line.Length - 2).Trim(), ConfigurationPath.KeyDelimiter);
continue;
} // key = value OR "value"
int separator = line.IndexOf('=');
if (separator < 0)
{
throw new FormatException(rawLine);
} string key = sectionPrefix + line.Substring(0, separator).Trim();
string value = line.Substring(separator + 1).Trim(); // Remove quotes
if (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"')
{
value = value.Substring(1, value.Length - 2);
} if (data.ContainsKey(key))
{
throw new FormatException(key);
} data[key] = value;
}
}
return data;
}

再来看看部分函数语义优化的代码

public class Ini
{
private static Ini instance = new Ini(); public Func<IPeeker<char>, bool> WhiteSpace = Chars.IngoreWhiteSpace.Map(i => i > 0); public Func<IPeeker<char>, bool> Comment = Chars.In(";#/").Delimited(Chars.NotCRLF.ToSlice().Opt(), Chars.IsCRLF, "Comment not right").Map((c, x, y, z) => c); public Func<IPeeker<char>, string> SectionName = Chars.Is('[').Delimited(Chars.Not(']').ToSlice().Once("Section name is required."), Chars.Is(']'), "Section name must end with ']'").Map((c, x, y, z) => y?.ToString()); public Func<IPeeker<char>, string> Key = Chars.Not('=').ToSlice().Once("key is required.").Map(i => i.ToString());
public Func<IPeeker<char>, char> Separater = Chars.Is('=').Once("Section name is required."); public Func<IPeeker<char>, string> Value = Chars.NotCRLF.ToSlice().Once("value is required.").Map(i =>
{
var v = i.ToString().Trim();
return v.StartsWith('"') ? v[1..^1] : v;
}); public IDictionary<string, string> ParseString(string content)
{
var input = Input.From(content);
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
while (input.TryPeek(out var v))
{
if (!(WhiteSpace(input) || Comment(input) || Section(input, dict)))
{
throw new NotSupportedException(v.ToString());
}
}
return dict;
} public bool SectionContentEnd(IPeeker<char> input)
{
return !input.TryPeek(out var v) || v is '[';
} public bool Section(StringPeeker input, Dictionary<string, string> dict)
{
var name = SectionName(input);
if (name == null) return false;
while (!SectionContentEnd(input))
{
if (WhiteSpace(input) || Comment(input))
{
continue;
}
SectionKV(input, dict, name);
}
return true;
} public void SectionKV(StringPeeker input, Dictionary<string, string> dict, string name)
{
var k = Key(input);
Separater(input);
var v = Value(input);
k = $"{name}:{k.Trim()}";
dict.Add(k, v.Trim());
} public static IDictionary<string, string> Parse(string content)
{
return instance.ParseString(content);
}
}

最后截取 部分 ini 解析库的代码 仅供参考

public IniData Parse(string iniDataString)
{
IniData iniData = (Configuration.CaseInsensitive ? new IniDataCaseInsensitive() : new IniData());
iniData.Configuration = Configuration.Clone();
if (string.IsNullOrEmpty(iniDataString))
{
return iniData;
} _errorExceptions.Clear();
_currentCommentListTemp.Clear();
_currentSectionNameTemp = null;
try
{
string[] array = iniDataString.Split(new string[2] { "\n", "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < array.Length; i++)
{
string text = array[i];
if (text.Trim() == string.Empty)
{
continue;
} try
{
ProcessLine(text, iniData);
}
catch (Exception ex)
{
ParsingException ex2 = new ParsingException(ex.Message, i + 1, text, ex);
if (Configuration.ThrowExceptionsOnError)
{
throw ex2;
} _errorExceptions.Add(ex2);
}
} if (_currentCommentListTemp.Count > 0)
{
if (iniData.Sections.Count > 0)
{
iniData.Sections.GetSectionData(_currentSectionNameTemp).TrailingComments.AddRange(_currentCommentListTemp);
}
else if (iniData.Global.Count > 0)
{
iniData.Global.GetLast().Comments.AddRange(_currentCommentListTemp);
} _currentCommentListTemp.Clear();
}
}
catch (Exception item)
{
_errorExceptions.Add(item);
if (Configuration.ThrowExceptionsOnError)
{
throw;
}
} if (HasError)
{
return null;
} return (IniData)iniData.Clone();
}

完整代码参考 https://github.com/fs7744/ruqu

通过解析库探究函数式抽象代价 ( ini 解析示例补充)的更多相关文章

  1. 爬虫(五)—— 解析库(二)beautiful soup解析库

    目录 解析库--beautiful soup 一.BeautifulSoup简介 二.安装模块 三.Beautiful Soup的基本使用 四.Beautiful Soup查找元素 1.查找文本.属性 ...

  2. 【开源】libinimini:适用于单片机的极简 ini 解析库

    介绍说明 最近自己基于 XR872 在做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件.我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. ...

  3. OpenStack配置解析库oslo.config的使用方法

    OpenStack的oslo项目旨在独立出系统中可重用的基础功能,oslo.config就是其中一个被广泛使用的库,该项工作的主要目的就是解析OpenStack中命令行(CLI)或配置文件(.conf ...

  4. C++的Json解析库:jsoncpp和boost(转)

    原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...

  5. [转]C++的Json解析库:jsoncpp和boost

    JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...

  6. golang常用库:配置文件解析库-viper使用

    一.viper简介 viper 配置解析库,是由大神 Steve Francia 开发,他在google领导着 golang 的产品开发,他也是 gohugo.io 的创始人之一,命令行解析库 cob ...

  7. Boost.JSON Boost的JSON解析库(1.75首发)

    目录 目录 Boost的1.75版本新库 JSON库简介 JSON的简单使用 编码 最通用的方法 使用std::initializer_list json对象的输出 两种对比 解码 简单的解码 增加错 ...

  8. 解析库beautifulsoup

    目录 一.介绍 二.遍历文档树 三.搜索文档树(过滤) 四.修改文档树 五.总结 一.介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的 ...

  9. Pugixml一种快速解析XML文件的开源解析库

    Pugixml是一个轻量级的C++ XML开源解析库,DOM形式的解析器.接口和丰富的遍历和修改操作,快速的解析,此外支持XPath1.0实现数据查询,支持unicode编码: 使用Pugixml可通 ...

  10. Tomjson - 一个"短小精悍"的 json 解析库

    Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...

随机推荐

  1. paddlespeech asr脚本demo

    概述 paddlespeech是百度飞桨平台的开源工具包,主要用于语音和音频的分析处理,其中包含多个可选模型,提供语音识别.语音合成.说话人验证.关键词识别.音频分类和语音翻译等功能. 本文介绍利用p ...

  2. C# ,使用“^”运算符对数字加密

    原理:"异或"运算符"^", 用于比较两个二进制数的响应位.计算过程如果两个二进制数的相应位都为1或两个二进制数的相应位都为0,则返回0:如果两个二进制数的相应 ...

  3. python常见面试题讲解(七)合并表记录

    题目描述 数据表记录包含表索引和数值(int范围的整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出. 输入描述: 先输入键值对的个数然后输入成对的in ...

  4. 深入理解Kafka核心设计及原理(一):初识Kafka

    转载请注明出处: 1.1 kafka简介 Kafka 起初是由 Linkedin 公司采用 Scala 语言开发的一个多分区.多副本且基于 ZooKeeper协调的分布式消息系统,现己被捐献给 Apa ...

  5. Chrome 控制台 换行编写js调试代码

    转载请注明出处: 在 chrome 浏览器的console 控制台编写 js 调试或验证代码时,每输一行换行时,就会执行当前行的函数,再重新换行输入时,就会将之前的代码忽略,这种方式就会导致 chro ...

  6. 【TouchGFX 】使用 CubeMX 创建 TouchGFX 工程时 LCD 死活不显示

    生成的代码死活无法让LCD显示,经两个晚上的分析验证是LTDC_CLK引脚速度设置为低速导致,经测试中速.高速.超高速都正常,真是冤,聊以此以示纪念

  7. Java进程内线程数量限制的相关学习

    Java进程内线程数量限制的相关学习 背景 还是之前出现 cannot create native thread 的问题的后续 周末在家学习了下如何在容器外抓取dump. 也验证了下能否开启超过宿主机 ...

  8. [转帖]haproxy

    HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性.负载均衡,以及基于TCP和HTTP的应用程序代理. HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保 ...

  9. [转帖]Linux之/etc/fstab文件讲解

    https://www.cnblogs.com/FengGeBlog/p/10178824.html /etc/fstab是用来存放文件系统的静态信息的文件.位于/etc/目录下,可以用命令less ...

  10. [转帖]三篇文章了解 TiDB 技术内幕 - 谈调度

    返回全部 申砾产品技术解读2017-06-06 为什么要进行调度 先回忆一下 三篇文章了解 TiDB 技术内幕 - 说存储提到的一些信息,TiKV 集群是 TiDB 数据库的分布式 KV 存储引擎,数 ...