目录

内容简介

园子里面很多博主都会为自己的博文创建目录,方便大家浏览。我很好奇大家是怎么做的,是不是有自动生成目录的工具可以推荐一下(我知道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])[\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>的目录。

双击打开后是这个样子,

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

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

工具改进

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

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

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

HTML目录生成工具的更多相关文章

  1. docfx 简单使用方法、自动生成目录的工具

    [摘要] 这是我编写的一个 Docfx 文档自动生成工具,只要写好 Markdown 文档,使用此工具可为目录.文件快速生成配置,然后直接使用 docfx 运行即可. https://github.c ...

  2. 【C#附源码】数据库文档生成工具支持(Excel+Html)

    [2015] 很多时候,我们在生成数据库文档时,使用某些工具,可效果总不理想,不是内容不详细,就是表现效果一般般.很多还是word.html的.看着真是别扭.本人习惯用Excel,所以闲暇时,就简单的 ...

  3. .NET平台开源项目速览(4).NET文档生成工具ADB及使用

    很久以前就使用ADB这个工具来生成项目的帮助文档.功能强大,在学习一些开源项目的过程中,官方没有提供CHM帮助文档,所以为了快速的了解项目结构和注释.就生成文档来自己看,非常好用.这也是一个学习方法吧 ...

  4. (转)Doxygen文档生成工具

    http://blog.csdn.net/lostaway/article/details/6446786 Doxygen 是一个支持 C/C++,以及其它多种语言的跨平台文档生成工具.如同 Java ...

  5. OrchardNoCMS模块生成工具命令简化

    OrchardNoCMS模块生成工具命令行简化列表:   目前只有codegen feature和cultures三个命令. 对应的都进行了参数简化. 例如:codegen module 简化为cod ...

  6. 数据字典生成工具之旅(5):DocX组件读取与写入Word

    由于上周工作比较繁忙,所以这篇文章等了这么久才写(预告一下,下一个章节正式进入NVelocity篇,到时会讲解怎么使用NVelocity做一款简易的代码生成器,敬请期待!),好了正式进入本篇内容. 这 ...

  7. 数据字典生成工具之旅(3):PowerDesign文件组成结构介绍及操作

    从这篇开始将正式讲解整个重要部分的实现细节,本篇讲解Pdm文件的解析.其实PDM文件就是XML文件,可以用Editplus或者VS打开查看.了解到这一点之后大家就能猜到,可以用解析XML的方式读取PD ...

  8. 数据字典生成工具之旅(4):NPOI操作EXECL

    这篇会介绍NPOI读写EXECL,读写EXECL的组件很多,可以使用微软自己的COM组件EXECL.exe读写,不过这种方式限制很大. 1:客户环境必须装Office(虽然现在机子上不装Office的 ...

  9. 数据字典生成工具之旅(6):NVelocity语法介绍及实例

    本章开始将会为大家讲解NVelocity的用法,并带领大家实现一个简单的代码生成器. NVelocity是一个基于.NET的模板引擎(template engine).它允许任何人仅仅简单的使用模板语 ...

随机推荐

  1. [08]APUE:进程控制

    [a] getpid / getppid / getuid / geteuid / getgid / getegid #include <unistd.h> pid_t getpid(vo ...

  2. LinuxMM--Memory Pressure

    Memory pressure定义在操作系统中,用户分配.文件缓存.网卡包缓冲区等等都会消耗内存.一旦出现内存紧张就会导致memory pressure.引发当某个任务需要请求内存时就有可能引发mem ...

  3. 在安卓下打包cocos2d-js 3.6项目with ProtoBuf.js

    项目用到了cocos2d-js 3.6和ProtoBuf.js,但是打包成apk时运行时总是报错(evaluatedOK == JS_FALSE),没有具体的文件和行号报错信息. 只能一个一个文件排查 ...

  4. __attribute__((packed))详解

      1. __attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法.这个功能是跟操作系统没关系,跟编译器有关 ...

  5. 《python核心编程》读书笔记——列表解析

    列表解析是列表类型的方法,这种方法结合了列表的方括弧.for循环.if语句. 用for把处理后的值放入列表: squared = [ x**2 for x in range(4) ] for i in ...

  6. [UCSD白板题] Take as Much Gold as Possible

    Problem Introduction This problem is about implementing an algorithm for the knapsack without repeti ...

  7. 【转】Linux 文件夹文件创建与删除

    [转自:Linux文件夹文件创建.删除 - 风生水起 - 博客园] 1. 删除文件夹 rm -rf  fileNamede> -删除文件夹实例:rm -rf /var/log/httpd/acc ...

  8. HTML和XHTML的一点事儿.

    什么是 HTML? HTML 是用来描述网页的一种语言. HTML 指的是超文本标记语言 (Hyper Text Markup Language) HTML 不是一种编程语言,而是一种标记语言 (ma ...

  9. c++使用stdint.h和inttypes.h

    我们有时候需要使用int有关的宏,比如PRId64,int64_t等,就需要包含那两个头文件. 由于那两个头文件是为c99默认使用的,c++要使用它可能要定义__STDC_FORMAT_MACROS, ...

  10. 第54讲:Scala中复合类型实战详解

    今天学习了scala的复合类型的内容,让我们通过实战来看看代码: trait Compound_Type1trait Compound_Type2class Compound_Type extends ...