• HTML目录生成工具


    目录

    内容简介

    园子里面很多博主都会为自己的博文创建目录,方便大家浏览。我很好奇大家是怎么做的,是不是有自动生成目录的工具可以推荐一下(我知道word可以,但是直接贴word文档会生成很多多余的html tag)。

    前几天写前端网页最佳实践目录项实在有点多,手动加起来太麻烦了,我尝试搜了下没有找到,于是写了几行代码来完成这工作。拿出来分享给有同样需要的朋友。

    工具代码

    using System;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace HtmlIndexGenerator
    {
        class Program
        {
            const string HeaderPattern = @"<h(?<level>[1-6])[sS]*?>[sS]*?</h([1-6])>";
            const string TagPattern = @"<[sS]*?>";
            const string IdPattern = "(id|name)="(?<id>[\s\S]*?)"";
    
            const int MaxHeaderLimit = 6;
    
            const string H1Style = @"font-weight:bold";
            const string H2Style = @"";
            const string H3Style = @"";
            const string H4Style = @"";
            const string H5Style = @"";
            const string H6Style = @"font-size:10px;";
    
            static string[] HeaderStyles = new string[]{
                H1Style,
                H2Style,
                H3Style,
                H4Style,
                H5Style,
                H6Style
            };
    
            static void Main(string[] args)
            {
                string fileName;
                int limit;
                ParseParameter(args, out fileName, out limit);
    
                string html = GetHtml(fileName);
    
                if (string.IsNullOrEmpty(html))
                    return;
    
                string index = GenerateIndex(html, limit);
    
                string outputFile = "index.htm";
                File.WriteAllText(outputFile, index, Encoding.UTF8);
                Console.WriteLine("{0} generated.", outputFile);
            }
    
            /// <summary>
            /// Prints help document.
            /// </summary>
            private static void PrintHelp()
            {
                Console.WriteLine("Usage: IndexGen.exe [filename] [-l] level");
                Console.WriteLine("-l: header level limit, -l 3 limit the output to <h3>");
                Console.WriteLine("Example: IndexGen.exe page.htm");
            }
    
            /// <summary>
            /// Parses command line paramters.
            /// </summary>
            /// <param name="args">Input parameters</param>
            /// <param name="fileName">Output parameter for parsed file name. Null if parse failed.</param>
            /// <param name="limit">Output parameter for header level limit.</param>
            private static void ParseParameter(string[] args, out string fileName, out int limit)
            {
                fileName = null;
                limit = MaxHeaderLimit;
    
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i].Equals("-l", StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (i + 1 >= args.Length || !int.TryParse(args[i + 1], out limit))
                        {
                            Console.WriteLine("Invalid parameter for -l");
                            PrintHelp();
                            return;
                        }
                    }
                }
                if (args.Length > 0)
                {
                    fileName = args[args.Length - 1];
                }
            }
    
            /// <summary>
            /// Reads html content according to specified file name.
            /// </summary>
            /// <param name="fileName">File name</param>
            /// <returns>Html content of the specific file.</returns>
            private static string GetHtml(string fileName)
            {
                string html = null;
                if (string.IsNullOrEmpty(fileName))
                {
                    Console.WriteLine("Specify a file name");
                    PrintHelp();
                    return html;
                }
                if (!File.Exists(fileName))
                {
                    Console.WriteLine("File {0} dose not exist", fileName);
                    PrintHelp();
                    return html;
                }
    
                // Auto defect file encoding.
                using (StreamReader reader = new StreamReader(fileName, detectEncodingFromByteOrderMarks: true))
                {
                    Encoding encoding = reader.CurrentEncoding;
                    html = File.ReadAllText(fileName, encoding);
                }
                return html;
            }
    
            /// <summary>
            /// Generates the index html.
            /// </summary>
            /// <param name="html">Html content of specified file.</param>
            /// <param name="limit">Header limit</param>
            /// <returns>Generated index html</returns>
            private static string GenerateIndex(string html, int limit)
            {
                Regex regex = new Regex(HeaderPattern, RegexOptions.IgnoreCase);
                Regex regexId = new Regex(IdPattern, RegexOptions.IgnoreCase);
                MatchCollection headerMatches = regex.Matches(html);
    
                int previousLevel = 1;
    
                StringBuilder indexBuilder = new StringBuilder();
                indexBuilder.Append("<div id="doc-index">");
                indexBuilder.Append("<ul>");
                foreach (Match headerMatch in headerMatches)
                {
                    int currentLevel = int.Parse(headerMatch.Groups["level"].Value);
                    string header = Regex.Replace(headerMatch.Value, TagPattern, string.Empty);
    
                    Match idMatch = regexId.Match(headerMatch.Value);
                    string id = idMatch.Success ? idMatch.Groups["id"].Value : null;
    
                    string link = string.IsNullOrEmpty(id) ? header : string.Format("<a href="#{0}">{1}</a>", id, header);
    
                    if (currentLevel == previousLevel)
                    {
                        indexBuilder.AppendFormat("<li style="{1}">{0}</li>", link, HeaderStyles[currentLevel - 1]);
                    }
                    else if (currentLevel > previousLevel && currentLevel <= limit)
                    {
                        indexBuilder.AppendFormat("<ul><li style="{1}">{0}</li>", link, HeaderStyles[currentLevel - 1]);
                        previousLevel = currentLevel;
                    }
                    else if (currentLevel < previousLevel)
                    {
                        indexBuilder.AppendFormat("</ul><li style="{1}">{0}</li>", link, HeaderStyles[currentLevel - 1]);
                        previousLevel = currentLevel;
                    }
                }
                indexBuilder.Append("</ul></div>");
                return indexBuilder.ToString();
            }
        }
    }
    

    使用方法

    将程序编译成执行文件,把博文存成本地文件,注意要存成unicode或utf-8,通过命令行运行。一个名叫index.htm的文件会生成在相同目录下。

    如果你只希望限制生成目录的级数,可以用 -l 参数指定,-l 3代表只生成<h1> 到<h3>的目录。

    1

    双击打开后是这个样子,

    2

    接下来需要做的是将生成的内容复制粘贴到博文你想放目录的地方。简单的目录就生成了,参看本文目录

    如果你想更改样式,可以直接修改代码中对不同的header的样式定义。

    工具改进

    这只是个小工具,肯定有很多让小伙伴们惊呆的不足,

    • 首先不应该用正则表达式解析html,具体原因可以看这里,如果真的要分析html,.net推荐使用htmlagilitypack,python推荐使用beautifulsoup,我这里不想再引入外部库,所以假设我们解析的html都是标准格式。
    • 另外我没写代码去生成标题的id属性,因为很多朋友希望id是有意义的名字而不简单的header1、lable2之类的,所以id还是需要你自己添加,不然超链接出不来。 <h1 id="intro"></h1>
    • 也尝试把这段代码转换成powershell脚本省了大家编译,这里有介绍如何做的方法,可惜插件也有硬伤,有些语法还不支持,比如using, out 参数等。

    另外如果大家有好的工具也请推荐下,这里抛砖引玉了。

  • 相关阅读:
    NetCore
    OAuth授权
    Vue混入:全局混入
    Vue作用域插槽:用作循环结构的模版
    Vue作用域插槽:基本用法
    Effect Hook
    State Hook
    表单组件中state依赖props
    Vue自定义指令
    Vue访问子组件实例或子元素
  • 原文地址:https://www.cnblogs.com/developersupport/p/html-index-generator.html
Copyright © 2020-2023  润新知