随笔 - 66  文章 - 0  评论 - 496  阅读 - 39万 

目录

内容简介

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

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

工具代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
 
namespace HtmlIndexGenerator
{
    class Program
    {
        const string HeaderPattern = @"<h(?<level>[1-6])[\s\S]*?>[\s\S]*?</h([1-6])>";
        const string TagPattern = @"<[\s\S]*?>";
        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 参数等。

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

posted on   微软互联网开发支持  阅读(8972)  评论(6编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示