首页 > 其他分享 >通过解析库探究函数式抽象代价 ( ini 解析示例补充)

通过解析库探究函数式抽象代价 ( ini 解析示例补充)

时间:2024-02-15 17:11:21浏览次数:43  
标签:return string 示例 value ini new input 解析 public

上一篇 用 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

标签:return,string,示例,value,ini,new,input,解析,public
From: https://www.cnblogs.com/fs7744/p/18016371

相关文章

  • tensorflow distributed training in tfx pipeline run by kubeflow
    1.deployworker,parameterserveronkubernetescluster1.1buildcontainerimageofworker,parameterserver$gitclonehttps://github.com/tensorflow/ecosystem.git$cdecosystem/distribution_strategy$sudonerdctlbuild--no-cache-ttf_std_server:......
  • .NET(C#)中new Dictionary(字典)初始化值(initializer默认值)
    ​  .NET(C#)中,当使用newDictionary<TKey,TValue>()初始化一个字典时,可以通过集合初始化器语法直接为字典添加初始键值对。如需要为字典设置默认值,通常是指为尚未在字典中明确设置的键提供一个默认返回值。Dictionary<TKey,TValue>类本身不直接支持默认值的概念,但可以通过......
  • Go 100 mistakes - #21: Inefficient slice initialization
          ConvertingoneslicetypeintoanotherisafrequentoperationforGodevelopers.As wehaveseen,ifthelengthofthefuturesliceisalreadyknown,thereisnogoodreasontoallocateanemptyslicefirst.Ouroptionsaretoallocat......
  • PyZelda 源码解析(全)
    .\Zelda-with-Python\Code\Debug.py#导入pygame和os模块importpygameimportos#设置当前工作目录为项目所在的目录,用于导入文件(特别是图片)os.chdir(os.path.dirname(os.path.abspath(__file__)))#初始化pygamepygame.init()#创建字体对象,用于在屏幕上显示调试信......
  • 解决pinia中更新值失败的问题
    来看一段代码,思考第19行代码能否正常输出?:asyncfunctionlogin(account_id:string,password:string):Promise<string>{leterror_message='';await$.ajax({url:'',type:"post",data:{//...........
  • javascript import export 简单示例
    概述import是ES6引入的新特性,它允许你以声明式的方式导入其他模块中的内容。require是Node.js中的特性,它允许你使用一个函数来加载和导入其他模块。使用方法utils.jsexportconstadd=(a,b)=>a+b;exportconstsubtract=(a,b)=>a-b; index.jsimport*asutilsfrom......
  • 2024九省联考数学备用卷选填解析
    答案\(1-5\)\(CADCA\)\(6-8\)\(DBD\)\(9\)\(ABD\)\(10\)\(AC\)\(11\)\(ACD\)\(12.\)\({(\frac{\sqrt{6}}{3},\frac{\sqrt{6}}{3}),(-\frac{\sqrt{6}}{3},-\frac{\sqrt{6}}{3})}\)\(13.\)奇\(\pi\)\(14.\)\(4+\frac{......
  • ini文件
    windows.ini配置文件的用法为什么要使用ini文件避免重新编译如果我们程序没有任何配置文件时,这样的程序对外是全封闭的一旦程序需要修改一些参数必须要修改程序代码本身并重新编译,为了避免这样,所以要用配置文件灵活性程序出厂后还能根据需要进行必要的配置,还可以使用系统......
  • Debug: tf_ditribute_strategy_worker.yaml: unknown field "spec.template.spec.node
    [ERROR:unknownfield"spec.template.spec.nodeAffinity"](base)maye@maye-Inspiron-5547:~/github_repository/tensorflow_ecosystem/distribution_strategy$kubectlapply-fmaye_template.yamlservice/dist-strat-example-worker-0createdservice/dis......
  • 通过解析库探究函数式抽象代价
    前因在春节前了解到Rust语言有一个叫nom的解析库它可以让你创建安全的解析器,而不会占用内存或影响性能。它依靠Rust强大的类型系统和内存安全来生成既正确又高效的解析器,并使用函数,宏和特征来抽象出容易出错的管道。nom核心是解析器组合器,而解析器组合器是高阶函数,可以......