contentLines);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/support/md/MarkdownFileToc.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.support.md;
7 |
8 | import com.github.houbb.markdown.toc.constant.VersionConstant;
9 | import com.github.houbb.markdown.toc.vo.TocGen;
10 | import com.github.houbb.markdown.toc.vo.config.TocConfig;
11 |
12 | import org.apiguardian.api.API;
13 |
14 | /**
15 | * 单个文件生成接口
16 | *
17 | * Created: 2018/7/27 下午2:53
18 | * Project: markdown-toc
19 | *
20 | * @author houbinbin
21 | */
22 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0)
23 | public interface MarkdownFileToc {
24 |
25 | /**
26 | * 生成单个文件的 toc
27 | * @param filePath 文件路径
28 | * @param config 生成配置
29 | * @return 生成的结果信息
30 | */
31 | TocGen genTocFile(final String filePath, final TocConfig config);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/support/md/impl/AtxMarkdownContentToc.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.support.md.impl;
7 |
8 | import com.github.houbb.heaven.util.lang.StringUtil;
9 | import com.github.houbb.heaven.util.util.CollectionUtil;
10 | import com.github.houbb.markdown.toc.constant.TocConstant;
11 | import com.github.houbb.markdown.toc.constant.VersionConstant;
12 | import com.github.houbb.markdown.toc.support.IncreaseMap;
13 | import com.github.houbb.markdown.toc.support.codeblock.ICodeBlock;
14 | import com.github.houbb.markdown.toc.support.codeblock.impl.AtxCodeBlock;
15 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc;
16 | import com.github.houbb.markdown.toc.vo.TocVo;
17 | import com.github.houbb.markdown.toc.vo.config.TocConfig;
18 | import org.apiguardian.api.API;
19 |
20 | import java.util.*;
21 |
22 | /**
23 | * ATX 根据内容返回目录
24 | *
25 | * Created: 2018/8/15 下午2:53
26 | * Project: markdown-toc
27 | *
28 | * @author houbinbin
29 | */
30 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_4)
31 | public class AtxMarkdownContentToc implements MarkdownContentToc {
32 |
33 | //region 内部属性
34 |
35 | /**
36 | * 配置信息
37 | * @since 1.0.5
38 | */
39 | private final TocConfig config;
40 |
41 | /**
42 | * toc str列表
43 | */
44 | private List tocStrList = new LinkedList<>();
45 |
46 | /**
47 | * toc值对象列表
48 | */
49 | private List tocVoList = new LinkedList<>();
50 |
51 | /**
52 | * 结果列表
53 | */
54 | private List resultList = new LinkedList<>();
55 |
56 | /**
57 | * 上一个节点
58 | */
59 | private TocVo previous;
60 |
61 | public AtxMarkdownContentToc(TocConfig config) {
62 | this.config = config;
63 | }
64 | //endregion
65 |
66 | @Override
67 | public List getPureTocList(List contentLines) {
68 | if (CollectionUtil.isEmpty(contentLines)) {
69 | return Collections.emptyList();
70 | }
71 |
72 | return buildTocList(contentLines);
73 | }
74 |
75 | @Override
76 | public List getPureContentList(List contentLines) {
77 | List resultList = new LinkedList<>(contentLines);
78 |
79 | //原先的目录过滤
80 | String firstLine = resultList.get(0);
81 | if (firstLine.startsWith(this.config.getTocHead())) {
82 | Iterator stringIterator = resultList.iterator();
83 | //开头
84 | nextAndRemove(stringIterator, 2);
85 | while (stringIterator.hasNext()) {
86 | String contentTrim = stringIterator.next().trim();
87 | if (contentTrim.startsWith(TocConstant.STAR)) {
88 | stringIterator.remove();
89 | } else {
90 | //直接跳出循环
91 | break;
92 | }
93 | }
94 | //移除当前换行
95 | if (stringIterator.hasNext()) {
96 | stringIterator.remove();
97 | }
98 | //最后的换行
99 | nextAndRemove(stringIterator, 1);
100 | }
101 |
102 | return resultList;
103 | }
104 |
105 | /**
106 | * 构建目录列表
107 | * v1.0.7 修复 bug:当 # 放在代码块中,则不认为是标题信息。
108 | * @param contentList 内容列表
109 | * @return 目录列表
110 | */
111 | private List buildTocList(final List contentList) {
112 | if (CollectionUtil.isEmpty(contentList)) {
113 | return Collections.emptyList();
114 | }
115 |
116 | //1. ATX 默认文件头
117 | String tocHead = config.getTocHead();
118 | if (StringUtil.isNotEmpty(tocHead)) {
119 | resultList.add(tocHead + TocConstant.RETURN_LINE);
120 | }
121 |
122 | //2. 所有 toc 行
123 | ICodeBlock codeBlock = AtxCodeBlock.newInstance();
124 | for (String string : contentList) {
125 | // 是否为代码块的处理
126 | codeBlock.put(string);
127 | if(codeBlock.isCodeBlock()) {
128 | continue;
129 | }
130 |
131 | String trim = string.trim();
132 | if (trim.startsWith(TocConstant.ASTERISK)) {
133 | tocStrList.add(trim);
134 | }
135 | }
136 |
137 | //3. 构建 tocVo
138 | //3.1 创建一个自增 map,用来处理重复名称
139 | IncreaseMap increaseMap = new IncreaseMap();
140 |
141 | TocVo root = TocVo.rootToc(increaseMap);
142 | root.setParent(null);
143 | //初始化根节点
144 | tocVoList.add(root);
145 | previous = root;
146 | for (String string : tocStrList) {
147 | addNewToc(string, increaseMap);
148 | }
149 |
150 | //4. 展现
151 | showToc(root.getChildren());
152 | resultList.add(TocConstant.RETURN_LINE);
153 |
154 | return resultList;
155 | }
156 |
157 |
158 | /**
159 | * 显示toc
160 | * v1.0.5 开始支持编号,此处默认从1开始。
161 | * @param tocVoList toc值对象列表
162 | */
163 | private void showToc(List tocVoList) {
164 | if (tocStrList.isEmpty()
165 | || CollectionUtil.isEmpty(tocVoList)) {
166 | return;
167 | }
168 | //v1.0.5 添加编号支持
169 | for (TocVo tocVo : tocVoList) {
170 | this.fillTocVo(tocVo);
171 | final String intent = tocVo.getIndent();
172 | String tocVoContent = intent + String.format(TocConstant.TOC_FORMAT,
173 | tocVo.getOrderDesc(), tocVo.getTocTitle(), tocVo.getTocHref());
174 | resultList.add(tocVoContent);
175 | showToc(tocVo.getChildren());
176 | }
177 | }
178 |
179 | /**
180 | * 填充信息
181 | * @param tocVo 原始对象
182 | */
183 | private void fillTocVo(TocVo tocVo) {
184 | final int level = tocVo.getLevel();
185 |
186 | //1. 前缀空格信息处理
187 | StringBuilder prefixBuilder = new StringBuilder();
188 | for (int i = 0; i < level - 1; i++) {
189 | prefixBuilder.append(TocConstant.TWO_BLANK);
190 | }
191 | tocVo.setIndent(prefixBuilder.toString());
192 |
193 | //2. 编号处理
194 | if(config.isOrder()) {
195 | // 递归获取对应的编号信息
196 | String orderDesc = buildOrderDesc(tocVo);
197 | tocVo.setOrderDesc(orderDesc);
198 | } else {
199 | tocVo.setOrderDesc(StringUtil.EMPTY);
200 | }
201 | }
202 |
203 | /**
204 | * 递归获取顺序描述
205 | * 1. 依次获取父类的 order,放在一个列表中。
206 | * 2. 终止的条件是当父类为 root
207 | * 3. 列表最后 reverse+用点连接起来。
208 | * @param tocVo 信息
209 | * @return 结果
210 | * @since 1.0.5
211 | */
212 | private String buildOrderDesc(final TocVo tocVo) {
213 | List orderList = new ArrayList<>();
214 | orderList.add(tocVo.getOrder());
215 |
216 | TocVo current = tocVo;
217 | while(current.getLevel() >= 1) {
218 | current = current.getParent();
219 | if(current.getLevel() >= 1) {
220 | orderList.add(current.getOrder());
221 | }
222 | }
223 |
224 | Collections.reverse(orderList);
225 | return CollectionUtil.join(orderList, TocConstant.DOT)+StringUtil.BLANK;
226 | }
227 |
228 | /**
229 | * 下一个并且移除元素
230 | *
231 | * @param stringIterator 迭代
232 | * @param times 次数
233 | */
234 | private void nextAndRemove(Iterator stringIterator, int times) {
235 | for (int i = 0; i < times; i++) {
236 | if (stringIterator.hasNext()) {
237 | String content = stringIterator.next();
238 | stringIterator.remove();
239 | }
240 | }
241 | }
242 |
243 | /**
244 | * 添加新的toc
245 | *
246 | * @param tocTrimStr toc trim str
247 | */
248 | private void addNewToc(String tocTrimStr, IncreaseMap increaseMap) {
249 | TocVo current = new TocVo(tocTrimStr, increaseMap);
250 |
251 | //1 级目录
252 | if (current.getLevel() == 1) {
253 | TocVo root = tocVoList.get(0);
254 | current.setParent(root);
255 | //添加到根目录
256 | root.getChildren().add(current);
257 | } else if (current.getLevel() <= previous.getLevel()) {
258 | TocVo previousParent = previous.getParent();
259 | current.setParent(previousParent);
260 | previousParent.getChildren().add(current);
261 | //上一节点的子节点
262 | } else if (current.getLevel() > previous.getLevel()) {
263 | current.setParent(previous);
264 | previous.getChildren().add(current);
265 | }
266 | // 统一设置 order 信息 1.0.5
267 | // 编号的下标从1开始
268 | TocVo parentToc = current.getParent();
269 | List childrenList = parentToc.getChildren();
270 | current.setOrder(childrenList.size());
271 |
272 | previous = current;
273 | }
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/support/md/impl/AtxMarkdownFileToc.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.support.md.impl;
7 |
8 | import com.github.houbb.heaven.util.io.FileUtil;
9 | import com.github.houbb.markdown.toc.constant.VersionConstant;
10 | import com.github.houbb.markdown.toc.exception.MarkdownTocRuntimeException;
11 | import com.github.houbb.markdown.toc.support.I18N;
12 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc;
13 | import com.github.houbb.markdown.toc.support.md.MarkdownFileToc;
14 | import com.github.houbb.markdown.toc.vo.TocGen;
15 | import com.github.houbb.markdown.toc.vo.config.TocConfig;
16 |
17 | import org.apiguardian.api.API;
18 |
19 | import java.io.IOException;
20 | import java.nio.file.Files;
21 | import java.nio.file.Path;
22 | import java.nio.file.Paths;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | /**
27 | * ATX 单个文件生成
28 | *
29 | * Created: 2018/7/27 下午2:53
30 | * Project: markdown-toc
31 | *
32 | * @author houbinbin
33 | */
34 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0)
35 | public class AtxMarkdownFileToc implements MarkdownFileToc {
36 |
37 | @Override
38 | public TocGen genTocFile(String filePath, TocConfig config) {
39 | Path path = Paths.get(filePath);
40 | return genTocForFile(path, config);
41 | }
42 |
43 | /**
44 | * 为单个文件生成 toc
45 | *
46 | * 1. 这里锁需要进行优化
47 | * 2. 粒度可以更加细致
48 | * @param path 文件路径
49 | * @param config 配置
50 | */
51 | private TocGen genTocForFile(final Path path, TocConfig config) {
52 | try {
53 | MarkdownContentToc markdownContentToc = new AtxMarkdownContentToc(config);
54 |
55 | //1. 校验文件后缀
56 | if(!FileUtil.isMdFile(path.toString())) {
57 | throw new MarkdownTocRuntimeException(I18N.get(I18N.Key.onlySupportMdFile));
58 | }
59 |
60 | //2. 获取 toc 列表
61 | List contentList = Files.readAllLines(path, config.getCharset());
62 | List trimTocContentList = markdownContentToc.getPureContentList(contentList);
63 | List tocList = markdownContentToc.getPureTocList(trimTocContentList);
64 |
65 | //3. 回写
66 | TocGen tocGen = new TocGen(path.toString(), tocList);
67 | if(config.isWrite()) {
68 | // 构建新的回写内容
69 | List resultList = new ArrayList<>(tocList);
70 | resultList.addAll(trimTocContentList);
71 |
72 | Files.write(path, resultList, config.getCharset());
73 | }
74 | return tocGen;
75 | } catch (IOException e) {
76 | throw new MarkdownTocRuntimeException(e);
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/util/MdTocTextHelper.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.util;
2 |
3 | import com.github.houbb.markdown.toc.core.IMarkdownTocText;
4 | import com.github.houbb.markdown.toc.core.MarkdownTocTextContext;
5 | import com.github.houbb.markdown.toc.core.impl.AtxMarkdownTocText;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 文本帮助类
11 | * @author binbin.hou
12 | * @since 1.1.0
13 | */
14 | public final class MdTocTextHelper {
15 |
16 | /**
17 | * 获取头信息
18 | * @param lines 行
19 | * @return 结果
20 | * @since 1.1.0
21 | */
22 | public static List getTocList(final List lines) {
23 | return getTocList(lines, false);
24 | }
25 |
26 | /**
27 | * 获取目录信息
28 | * @param lines 行
29 | * @param orderNum 编号
30 | * @return 结果
31 | * @since 1.1.0
32 | */
33 | public static List getTocList(final List lines, boolean orderNum) {
34 | MarkdownTocTextContext context = new MarkdownTocTextContext();
35 | context.lines(lines).order(orderNum);
36 |
37 | IMarkdownTocText tocText = new AtxMarkdownTocText(context);
38 |
39 | return tocText.getTocList();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/util/ThreadLocalUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.util;
7 |
8 | import com.github.houbb.markdown.toc.constant.VersionConstant;
9 | import com.github.houbb.markdown.toc.support.md.MarkdownFileToc;
10 | import com.github.houbb.markdown.toc.support.md.impl.AtxMarkdownFileToc;
11 | import com.github.houbb.markdown.toc.vo.TocGen;
12 | import com.github.houbb.markdown.toc.vo.config.TocConfig;
13 |
14 | import org.apiguardian.api.API;
15 |
16 | /**
17 | * threadlocal 工具类
18 | *
19 | * Created: 2018/7/27 下午6:49
20 | * Project: markdown-toc
21 | *
22 | * @author houbinbin
23 | * @version 1.0
24 | * @since JDK 1.7
25 | */
26 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0)
27 | public class ThreadLocalUtil {
28 |
29 | /**
30 | * @since 1.0.8
31 | */
32 | private ThreadLocalUtil(){}
33 |
34 | /**
35 | * 用于保存当前线程的信息
36 | */
37 | private static final ThreadLocal FILE_TOC_THREAD_LOCAL = new ThreadLocal<>();
38 |
39 | /**
40 | * 生成文件
41 | * @param filePath 文件路径
42 | * @param tocConfig 配置信息
43 | * @return 目录结构
44 | */
45 | public static TocGen genTocFile(final String filePath, TocConfig tocConfig) {
46 | MarkdownFileToc fileToc = getMarkdownFileToc();
47 | return fileToc.genTocFile(filePath, tocConfig);
48 | }
49 |
50 | /**
51 | * 清空
52 | * 1. 建议在每个线程执行结束,调用
53 | */
54 | public static void clear() {
55 | FILE_TOC_THREAD_LOCAL.remove();
56 | }
57 |
58 | /**
59 | * 使用 threadLocal 获取分词器对象
60 | * @return 当前线程的分词器
61 | */
62 | private static MarkdownFileToc getMarkdownFileToc() {
63 | MarkdownFileToc fileToc = FILE_TOC_THREAD_LOCAL.get();
64 | if(null == fileToc) {
65 | fileToc = new AtxMarkdownFileToc();
66 | FILE_TOC_THREAD_LOCAL.set(fileToc);
67 | }
68 | return fileToc;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/vo/TocGen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.vo;
7 |
8 | import com.github.houbb.markdown.toc.constant.VersionConstant;
9 |
10 | import org.apiguardian.api.API;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * toc 内容
16 | *
17 | * @author bbhou
18 | * @version 1.0.0
19 | * @since 1.0.0, 2018/01/30
20 | */
21 | @API(status = API.Status.MAINTAINED, since = VersionConstant.V_1_0_0)
22 | public class TocGen {
23 |
24 | /**
25 | * 文件路径
26 | */
27 | private final String filePath;
28 |
29 | /**
30 | * toc 的相关内容
31 | */
32 | private final List tocLines;
33 |
34 | public TocGen(String filePath, List tocLines) {
35 | this.filePath = filePath;
36 | this.tocLines = tocLines;
37 | }
38 |
39 | public String getFilePath() {
40 | return filePath;
41 | }
42 |
43 | public List getTocLines() {
44 | return tocLines;
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return "TocGen{" +
50 | "filePath='" + filePath + '\'' +
51 | ", tocLines=" + tocLines +
52 | '}';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/vo/TocVo.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.vo;
2 |
3 | import com.github.houbb.markdown.toc.constant.VersionConstant;
4 | import com.github.houbb.markdown.toc.support.IncreaseMap;
5 |
6 | import org.apiguardian.api.API;
7 |
8 | import java.util.LinkedList;
9 | import java.util.List;
10 |
11 | /**
12 | * toc值对象
13 | *
14 | * @author bbhou
15 | * @version 1.0.0
16 | * @since 1.0.0, 2018/01/30
17 | */
18 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0)
19 | public class TocVo {
20 | /**
21 | * ROOT 节点名称
22 | */
23 | private static final String ROOT_NAME = "ROOT";
24 |
25 | /**
26 | * 起源
27 | */
28 | private String origin;
29 |
30 | /**
31 | * 水平
32 | */
33 | private int level;
34 |
35 | /**
36 | * toc标题
37 | */
38 | private String tocTitle;
39 |
40 | /**
41 | * toc href
42 | */
43 | private String tocHref;
44 |
45 | /**
46 | * 父节点
47 | */
48 | private TocVo parent;
49 |
50 | /**
51 | * 孩子
52 | */
53 | private List children = new LinkedList<>();
54 |
55 | /**
56 | * 自增 MAP
57 | */
58 | private final IncreaseMap increaseMap;
59 |
60 | /**
61 | * 编号序号
62 | * @since 1.0.5
63 | */
64 | private int order;
65 |
66 | /**
67 | * 编号序号
68 | * @since 1.0.5
69 | */
70 | private String orderDesc;
71 |
72 | /**
73 | * 空格缩进
74 | * @since 1.0.5
75 | */
76 | private String indent;
77 |
78 | /**
79 | * toc值对象
80 | *
81 | * @param origin 起源
82 | * @param increaseMap map
83 | */
84 | public TocVo(String origin, IncreaseMap increaseMap) {
85 | this.origin = origin;
86 | this.increaseMap = increaseMap;
87 | init();
88 | }
89 |
90 | /**
91 | * 初始化
92 | */
93 | private void init() {
94 | if (ROOT_NAME.equals(this.origin)) {
95 | return;
96 | }
97 |
98 | String[] strings = this.origin.split("\\s+");
99 | this.tocTitle = this.origin.substring(strings[0].length()).trim();
100 | this.tocHref = increaseMap.buildActualName(tocTitle);
101 | this.level = strings[0].length();
102 | }
103 |
104 | /**
105 | * 根源toc
106 | *
107 | * @param increaseMap map 集合
108 | * @return com.github.houbb.markdown.toc.vo.TocVo
109 | */
110 | public static TocVo rootToc(IncreaseMap increaseMap) {
111 | TocVo tocVo = new TocVo(ROOT_NAME, increaseMap);
112 | tocVo.setLevel(0);
113 | return tocVo;
114 | }
115 |
116 |
117 | /**
118 | * 得到起源
119 | *
120 | * @return java.lang.String
121 | */
122 | public String getOrigin() {
123 | return origin;
124 | }
125 |
126 | /**
127 | * 设置原点
128 | *
129 | * @param origin 起源
130 | */
131 | public void setOrigin(String origin) {
132 | this.origin = origin;
133 | }
134 |
135 | /**
136 | * 得到水平
137 | *
138 | * @return int
139 | */
140 | public int getLevel() {
141 | return level;
142 | }
143 |
144 | /**
145 | * 设定等级
146 | *
147 | * @param level 水平
148 | */
149 | public void setLevel(int level) {
150 | this.level = level;
151 | }
152 |
153 | /**
154 | * 得到toc标题
155 | *
156 | * @return java.lang.String
157 | */
158 | public String getTocTitle() {
159 | return tocTitle;
160 | }
161 |
162 | /**
163 | * 设置toc标题
164 | *
165 | * @param tocTitle toc标题
166 | */
167 | public void setTocTitle(String tocTitle) {
168 | this.tocTitle = tocTitle;
169 | }
170 |
171 | /**
172 | * 得到toc href
173 | *
174 | * @return java.lang.String
175 | */
176 | public String getTocHref() {
177 | return tocHref;
178 | }
179 |
180 | /**
181 | * 设置为hc
182 | *
183 | * @param tocHref toc href
184 | */
185 | public void setTocHref(String tocHref) {
186 | this.tocHref = tocHref;
187 | }
188 |
189 | /**
190 | * 得到孩子
191 | *
192 | * @return java.util.List
193 | */
194 | public List getChildren() {
195 | return children;
196 | }
197 |
198 | /**
199 | * 设置孩子
200 | *
201 | * @param children 孩子
202 | */
203 | public void setChildren(List children) {
204 | this.children = children;
205 | }
206 |
207 | /**
208 | * 得到父母
209 | *
210 | * @return com.github.houbb.markdown.toc.vo.TocVo
211 | */
212 | public TocVo getParent() {
213 | return parent;
214 | }
215 |
216 | /**
217 | * 设置父母
218 | *
219 | * @param parent 亲
220 | */
221 | public void setParent(TocVo parent) {
222 | this.parent = parent;
223 | }
224 |
225 | public int getOrder() {
226 | return order;
227 | }
228 |
229 | public void setOrder(int order) {
230 | this.order = order;
231 | }
232 |
233 | public String getOrderDesc() {
234 | return orderDesc;
235 | }
236 |
237 | public void setOrderDesc(String orderDesc) {
238 | this.orderDesc = orderDesc;
239 | }
240 |
241 | public String getIndent() {
242 | return indent;
243 | }
244 |
245 | public void setIndent(String indent) {
246 | this.indent = indent;
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/markdown/toc/vo/config/TocConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.vo.config;
7 |
8 | import com.github.houbb.markdown.toc.constant.VersionConstant;
9 |
10 | import org.apiguardian.api.API;
11 |
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * 配置文件
16 | *
17 | * Created: 2018/7/27 下午2:58
18 | * Project: markdown-toc
19 | *
20 | * @author houbinbin
21 | * @since 1.0.5 进行调整
22 | */
23 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0)
24 | public class TocConfig {
25 |
26 | /**
27 | * 编码(默认为utf-8)
28 | */
29 | private Charset charset;
30 |
31 | /**
32 | * 是否包含子文件夹下的文件(默认为包含)
33 | */
34 | private boolean subTree;
35 |
36 | /**
37 | * 是否写入到文件(默认写入)
38 | */
39 | private boolean write;
40 |
41 | /**
42 | * 是否添加编号
43 | * ps: 此处不再使用 immutable 模式,直接 getter/setter 处理
44 | * @since 1.0.5
45 | */
46 | private boolean order;
47 |
48 | /**
49 | * 头信息
50 | * @since 1.2.0
51 | */
52 | private String tocHead;
53 |
54 | public Charset getCharset() {
55 | return charset;
56 | }
57 |
58 | public void setCharset(Charset charset) {
59 | this.charset = charset;
60 | }
61 |
62 | public boolean isSubTree() {
63 | return subTree;
64 | }
65 |
66 | public void setSubTree(boolean subTree) {
67 | this.subTree = subTree;
68 | }
69 |
70 | public boolean isWrite() {
71 | return write;
72 | }
73 |
74 | public void setWrite(boolean write) {
75 | this.write = write;
76 | }
77 |
78 | public boolean isOrder() {
79 | return order;
80 | }
81 |
82 | public void setOrder(boolean order) {
83 | this.order = order;
84 | }
85 |
86 | public String getTocHead() {
87 | return tocHead;
88 | }
89 |
90 | public void setTocHead(String tocHead) {
91 | this.tocHead = tocHead;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/resources/i18n/MarkdownToc.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2018. houbinbin Inc.
3 | # markdown-toc All rights reserved.
4 | #
5 |
6 | # markdown toc properties file.
7 |
8 | pathIsNotDirectory=%s path is not a directory
9 |
10 | pathIsNotAllowEmpty=Path is not allow empty
11 |
12 | onlySupportMdFile=Only support markdown file
13 |
--------------------------------------------------------------------------------
/src/main/resources/i18n/MarkdownToc_en.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2018. houbinbin Inc.
3 | # markdown-toc All rights reserved.
4 | #
5 |
6 | # markdown toc properties file.
7 |
8 | pathIsNotDirectory=%s path is not a directory
9 |
10 | pathIsNotAllowEmpty=Path is not allow empty
11 |
12 | onlySupportMdFile=Only support markdown file
--------------------------------------------------------------------------------
/src/main/resources/i18n/MarkdownToc_zh_CN.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2018. houbinbin Inc.
3 | # markdown-toc All rights reserved.
4 | #
5 |
6 | # markdown toc properties file.
7 |
8 | pathIsNotDirectory=%s \u6587\u4EF6\u8DEF\u5F84\u5FC5\u987B\u662F\u6587\u4EF6\u5939
9 |
10 | pathIsNotAllowEmpty=\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5141\u8BB8\u4E3A\u7A7A
11 |
12 | onlySupportMdFile=\u53EA\u652F\u6301 markdown \u683C\u5F0F\u6587\u4EF6
13 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/constant/TocConstantTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.constant;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * TocConstant Tester.
7 | *
8 | * @author author
9 | * @since 2018-01-30 15:11:47.245
10 | * @version 1.0
11 | */
12 | public class TocConstantTest {
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/core/MarkdownTocTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.core;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * MarkdownToc Tester.
7 | *
8 | * @author author
9 | * @since 2018-01-30 15:11:47.248
10 | * @version 1.0
11 | */
12 | public class MarkdownTocTest {
13 |
14 | /**
15 | *
16 | * Method: genToc(url, charset)
17 | */
18 | @Test
19 | public void genTocTest() throws Exception {
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownI18NTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.core.impl;
7 |
8 | import com.github.houbb.markdown.toc.util.TestPathUtil;
9 | import org.junit.Assert;
10 | import org.junit.Test;
11 |
12 | import java.util.Locale;
13 |
14 | /**
15 | * AtxMarkdownToc 国家化编码测试
16 | *
17 | * @author author
18 | * @version 1.0
19 | * @since 2018-01-30 15:11:47.256
20 | */
21 | public class AtxMarkdownI18NTest {
22 |
23 | @Test
24 | public void pathMustDirEnglish() {
25 | try {
26 | Locale.setDefault(new Locale("en", "US"));
27 | String path = TestPathUtil.getAppRootPath("subNotExists");
28 | AtxMarkdownToc.newInstance()
29 | .genTocDir(path);
30 | } catch (Exception e) {
31 | final String expectedMsg = "D:\\github\\markdown-toc/src/test/resources/subNotExists path is not a directory";
32 | final String msg = e.getMessage();
33 | Assert.assertEquals(expectedMsg, msg);
34 | }
35 | }
36 |
37 | @Test
38 | public void pathMustDirChinese() {
39 | try {
40 | Locale.setDefault(new Locale("zh", "CN"));
41 | String path = TestPathUtil.getAppRootPath("subNotExists");
42 | AtxMarkdownToc.newInstance()
43 | .genTocDir(path);
44 | } catch (Exception e) {
45 | final String expectedMsg = "D:\\github\\markdown-toc/src/test/resources/subNotExists 文件路径必须是文件夹";
46 | final String msg = e.getMessage();
47 | Assert.assertEquals(expectedMsg, msg);
48 | }
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.core.impl;
7 |
8 | import com.github.houbb.markdown.toc.util.TestPathUtil;
9 | import com.github.houbb.markdown.toc.vo.TocGen;
10 |
11 | import org.junit.Assert;
12 | import org.junit.Test;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * AtxMarkdownToc 文件夹测试
18 | *
19 | * @author author
20 | * @version 1.0
21 | * @since 2018-01-30 15:11:47.256
22 | */
23 | public class AtxMarkdownTocDirTest {
24 |
25 | /**
26 | * 不包含子元素-测试
27 | */
28 | @Test
29 | public void notSubTreeTest() {
30 | String path = TestPathUtil.getAppRootPath("sub");
31 | List tocGens = AtxMarkdownToc.newInstance()
32 | .subTree(false)
33 | .genTocDir(path);
34 |
35 | final int size = tocGens.size();
36 | Assert.assertEquals(2, size);
37 | }
38 |
39 | /**
40 | * 无 md 文件测试
41 | */
42 | @Test
43 | public void noMdTest() {
44 | String path = TestPathUtil.getAppRootPath("sub0");
45 | List tocGens = AtxMarkdownToc.newInstance()
46 | .subTree(false)
47 | .write(false)
48 | .genTocDir(path);
49 |
50 | final int size = tocGens.size();
51 | Assert.assertEquals(0, size);
52 | }
53 |
54 | /**
55 | * 单 md 文件测试
56 | */
57 | @Test
58 | public void oneMdTest() {
59 | String path = TestPathUtil.getAppRootPath("sub1");
60 | List tocGens = AtxMarkdownToc.newInstance()
61 | .subTree(false)
62 | .write(false)
63 | .genTocDir(path);
64 |
65 | final int size = tocGens.size();
66 | Assert.assertEquals(1, size);
67 | }
68 |
69 | /**
70 | * 普通-测试
71 | * 1. 默认进行文件的递归遍历
72 | */
73 | @Test
74 | public void commonTest() {
75 | String path = TestPathUtil.getAppRootPath("sub");
76 | List tocGens = AtxMarkdownToc.newInstance()
77 | .genTocDir(path);
78 | final int size = tocGens.size();
79 | Assert.assertEquals(6, size);
80 | }
81 |
82 | /**
83 | * 特殊符号测试
84 | */
85 | @Test
86 | public void specialTest() {
87 | String path = TestPathUtil.getAppRootPath("special");
88 | List tocGens = AtxMarkdownToc.newInstance()
89 | .subTree(true)
90 | .genTocDir(path);
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.core.impl;
2 |
3 | import com.github.houbb.markdown.toc.core.MarkdownToc;
4 | import com.github.houbb.markdown.toc.util.TestPathUtil;
5 | import com.github.houbb.markdown.toc.vo.TocGen;
6 |
7 | import org.junit.Assert;
8 | import org.junit.Test;
9 |
10 | /**
11 | * AtxMarkdownToc 单个文件测试
12 | *
13 | * @author author
14 | * @version 1.0
15 | * @since 2018-01-30 15:11:47.256
16 | */
17 | public class AtxMarkdownTocFileTest {
18 |
19 | /**
20 | * 普通-fluent 写法
21 | */
22 | @Test
23 | public void commonFluentTest() {
24 | String path = TestPathUtil.getAppRootPath("common.md");
25 | TocGen tocGen = AtxMarkdownToc.newInstance()
26 | .genTocFile(path);
27 |
28 | Assert.assertEquals(8, tocGen.getTocLines().size());
29 | }
30 |
31 | /**
32 | * 普通-新建接口的方式
33 | */
34 | @Test
35 | public void commonInterfaceTest() {
36 | String path = TestPathUtil.getAppRootPath("common.md");
37 |
38 | MarkdownToc markdownToc = new AtxMarkdownToc();
39 | TocGen tocGen = markdownToc.genTocFile(path);
40 |
41 | Assert.assertEquals(8, tocGen.getTocLines().size());
42 | }
43 |
44 | /**
45 | * 中文名称测试
46 | */
47 | @Test
48 | public void chineseFileNameTest() {
49 | String path = TestPathUtil.getAppRootPath("中文名称.md");
50 | TocGen tocGen = AtxMarkdownToc.newInstance()
51 | .genTocFile(path);
52 |
53 | Assert.assertEquals(10, tocGen.getTocLines().size());
54 | }
55 |
56 | /**
57 | * 特殊文件编码测试
58 | */
59 | @Test
60 | public void charsetGbkTest() {
61 | String path = TestPathUtil.getAppRootPath("README-GBK.md");
62 | TocGen tocGen = AtxMarkdownToc.newInstance()
63 | .charset("GBK")
64 | .genTocFile(path);
65 |
66 | Assert.assertEquals(13, tocGen.getTocLines().size());
67 | }
68 |
69 | /**
70 | * 不写入文件测试
71 | */
72 | @Test
73 | public void notWriteTest() {
74 | String path = TestPathUtil.getAppRootPath("common.md");
75 |
76 | TocGen tocGen = AtxMarkdownToc.newInstance()
77 | .write(false)
78 | .genTocFile(path);
79 |
80 | Assert.assertEquals(8, tocGen.getTocLines().size());
81 | }
82 |
83 | /**
84 | * 编号测试
85 | */
86 | @Test
87 | public void orderTest() {
88 | String path = TestPathUtil.getAppRootPath("common.md");
89 |
90 | TocGen tocGen = AtxMarkdownToc.newInstance()
91 | .order(true)
92 | .genTocFile(path);
93 |
94 | Assert.assertEquals(8, tocGen.getTocLines().size());
95 | }
96 |
97 | /**
98 | * 多层目录测试
99 | */
100 | @Test
101 | public void nLevelTest() {
102 | String path = TestPathUtil.getAppRootPath("N-LEVEL.md");
103 |
104 | TocGen tocGen = AtxMarkdownToc.newInstance()
105 | .genTocFile(path);
106 |
107 | Assert.assertEquals(21, tocGen.getTocLines().size());
108 | }
109 |
110 | /**
111 | * readme测试
112 | */
113 | @Test
114 | public void readMeTest() {
115 | String path = TestPathUtil.getAppRootPath("readme/README.md");
116 |
117 | TocGen tocGen = AtxMarkdownToc.newInstance()
118 | .order(true)
119 | .genTocFile(path);
120 |
121 | Assert.assertEquals(17, tocGen.getTocLines().size());
122 | }
123 |
124 | /**
125 | * 代码块测试
126 | * @since 1.0.7
127 | */
128 | @Test
129 | public void codeBlockTest() {
130 | String path = TestPathUtil.getAppRootPath("CODE_BLOCK.md");
131 |
132 | TocGen tocGen = AtxMarkdownToc.newInstance()
133 | .order(true)
134 | .genTocFile(path);
135 |
136 | Assert.assertEquals(15, tocGen.getTocLines().size());
137 | }
138 |
139 | /**
140 | * 演示配置测试
141 | */
142 | @Test
143 | public void justConfigTest() {
144 | AtxMarkdownToc.newInstance()
145 | .charset("UTF-8")
146 | .write(true)
147 | .subTree(true)
148 | .order(true);
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/exception/MarkdownTocRuntimeExceptionTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.exception;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * MarkdownTocRuntimeException Tester.
7 | *
8 | * @author author
9 | * @since 2018-01-30 15:11:47.263
10 | * @version 1.0
11 | */
12 | public class MarkdownTocRuntimeExceptionTest {
13 |
14 | /**
15 | *
16 | * Method: MarkdownTocRuntimeException()
17 | */
18 | @Test
19 | public void MarkdownTocRuntimeExceptionTest() throws Exception {
20 | }
21 |
22 | /**
23 | *
24 | * Method: MarkdownTocRuntimeException(message)
25 | */
26 | @Test
27 | public void MarkdownTocRuntimeExceptionMessageTest() throws Exception {
28 | }
29 |
30 | /**
31 | *
32 | * Method: MarkdownTocRuntimeException(message, cause)
33 | */
34 | @Test
35 | public void MarkdownTocRuntimeExceptionMessageCauseTest() throws Exception {
36 | }
37 |
38 | /**
39 | *
40 | * Method: MarkdownTocRuntimeException(cause)
41 | */
42 | @Test
43 | public void MarkdownTocRuntimeExceptionCauseTest() throws Exception {
44 | }
45 |
46 | /**
47 | *
48 | * Method: MarkdownTocRuntimeException(message, cause, enableSuppression, writableStackTrace)
49 | */
50 | @Test
51 | public void MarkdownTocRuntimeExceptionMessageCauseEnableSuppressionWritableStackTraceTest() throws Exception {
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/support/AtxMarkdownContentTocTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.support;
7 |
8 | import com.github.houbb.heaven.util.io.FileUtil;
9 | import com.github.houbb.heaven.util.util.CollectionUtil;
10 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc;
11 | import com.github.houbb.markdown.toc.support.md.impl.AtxMarkdownContentToc;
12 | import com.github.houbb.markdown.toc.util.TestPathUtil;
13 | import com.github.houbb.markdown.toc.vo.config.TocConfig;
14 | import org.junit.Assert;
15 | import org.junit.Before;
16 | import org.junit.Test;
17 |
18 | import java.io.File;
19 | import java.util.List;
20 |
21 | /**
22 | * atx 内容测试
23 | *
24 | * Created: 2018/8/15 下午3:02
25 | * Project: markdown-toc
26 | *
27 | * @author houbinbin
28 | * @version 1.0
29 | * @since JDK 1.7
30 | */
31 | public class AtxMarkdownContentTocTest {
32 |
33 |
34 | private MarkdownContentToc markdownContentToc;
35 |
36 | @Before
37 | public void before() {
38 | TocConfig config = new TocConfig();
39 | markdownContentToc = new AtxMarkdownContentToc(config);
40 | }
41 |
42 | @Test
43 | public void emptyTest() {
44 | List lines = getLines("empty.md");
45 | List tocs = markdownContentToc.getPureTocList(lines);
46 | Assert.assertTrue(CollectionUtil.isEmpty(tocs));
47 | }
48 |
49 | @Test
50 | public void emptyContentTest() {
51 | List lines = getLines("empty-content.md");
52 | List pureLines = markdownContentToc.getPureContentList(lines);
53 | List tocs = markdownContentToc.getPureTocList(pureLines);
54 | Assert.assertTrue(CollectionUtil.isEmpty(tocs));
55 | }
56 |
57 | @Test
58 | public void commonTest() {
59 | List lines = getLines("common.md");
60 | List tocs = markdownContentToc.getPureTocList(lines);
61 |
62 | Assert.assertEquals(9, tocs.size());
63 | showTocs(tocs);
64 | }
65 |
66 | @Test
67 | public void nLevelTest() {
68 | List lines = getLines("N-LEVEL.md");
69 | List tocs = markdownContentToc.getPureTocList(lines);
70 |
71 | Assert.assertEquals(22, tocs.size());
72 | showTocs(tocs);
73 | }
74 |
75 | /**
76 | * 代码块测试
77 | * @since 1.0.7
78 | */
79 | @Test
80 | public void codeBlockTest() {
81 | List lines = getLines("CODE_BLOCK.md");
82 | List tocs = markdownContentToc.getPureTocList(lines);
83 |
84 | showTocs(tocs);
85 | }
86 |
87 | /**
88 | * 展现目录
89 | * @param tocs toc lines
90 | */
91 | private void showTocs(final List tocs) {
92 | Assert.assertFalse(CollectionUtil.isEmpty(tocs));
93 | for(String string : tocs) {
94 | System.out.println(string);
95 | }
96 | }
97 |
98 | /**
99 | * 获取文件内容
100 | * @param filePath 文件路径
101 | * @return 文件内容列表
102 | */
103 | private List getLines(final String filePath) {
104 | String fullPath = TestPathUtil.getAppRootPath(filePath);
105 | try {
106 | return FileUtil.getFileContentEachLine(new File(fullPath), 0);
107 | } catch (Exception e) {
108 | throw new RuntimeException(e);
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/util/MdTocTextHelperTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.util;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * 基本的测试
10 | *
11 | * @since 1.1.0
12 | */
13 | public class MdTocTextHelperTest {
14 |
15 | @Test
16 | public void helloTest() {
17 | List lines = new ArrayList<>();
18 | lines.add("# 标题1");
19 | lines.add("这是一行内容");
20 | lines.add("# 标题2");
21 | lines.add("这也是一行内容");
22 |
23 | List tocList = MdTocTextHelper.getTocList(lines);
24 | foreachPrint(tocList);
25 | }
26 |
27 | @Test
28 | public void orderNumTest() {
29 | List lines = new ArrayList<>();
30 | lines.add("# 标题1");
31 | lines.add("这是一行内容");
32 | lines.add("# 标题2");
33 | lines.add("这也是一行内容");
34 |
35 | List tocList = MdTocTextHelper.getTocList(lines, true);
36 | foreachPrint(tocList);
37 | }
38 |
39 | /**
40 | * 循环处理集合
41 | *
42 | * @param tocList 集合
43 | * @since 0.1.93
44 | */
45 | public static void foreachPrint(List tocList) {
46 | for(String toc : tocList) {
47 | System.out.println(toc);
48 | }
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/util/TestPathUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018. houbinbin Inc.
3 | * markdown-toc All rights reserved.
4 | */
5 |
6 | package com.github.houbb.markdown.toc.util;
7 |
8 | import org.junit.Test;
9 |
10 | import java.io.File;
11 |
12 | /**
13 | * 测试路径工具类
14 | *
15 | * Created: 2018/7/5 下午2:22
16 | * Project: markdown-toc
17 | *
18 | * @author houbinbin
19 | * @version 1.0
20 | * @since JDK 1.7
21 | */
22 | public class TestPathUtil {
23 |
24 |
25 | /**
26 | * 获取项目根路径+测试资源文件路径+XXX
27 | * @param relativeTest 相对路径
28 | * @return 绝对路径
29 | */
30 | public static String getAppRootPath(final String relativeTest) {
31 | File emptyFile = new File("");
32 | String root = emptyFile.getAbsolutePath();
33 | return root+"/src/test/resources/"+relativeTest;
34 | }
35 |
36 | @Test
37 | public void getAppRootPathTest() {
38 | System.out.println(getAppRootPath("common.md"));
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/markdown/toc/vo/TocVoTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.markdown.toc.vo;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * TocVo Tester.
7 | *
8 | * @author author
9 | * @since 2018-01-30 15:11:47.253
10 | * @version 1.0
11 | */
12 | public class TocVoTest {
13 |
14 | /**
15 | *
16 | * Method: TocVo(origin)
17 | */
18 | @Test
19 | public void TocVoTest() throws Exception {
20 | }
21 |
22 | /**
23 | *
24 | * Method: rootToc()
25 | */
26 | @Test
27 | public void rootTocTest() throws Exception {
28 | }
29 |
30 | /**
31 | *
32 | * Method: getOrigin()
33 | */
34 | @Test
35 | public void getOriginTest() throws Exception {
36 | }
37 |
38 | /**
39 | *
40 | * Method: setOrigin(origin)
41 | */
42 | @Test
43 | public void setOriginTest() throws Exception {
44 | }
45 |
46 | /**
47 | *
48 | * Method: getLevel()
49 | */
50 | @Test
51 | public void getLevelTest() throws Exception {
52 | }
53 |
54 | /**
55 | *
56 | * Method: setLevel(level)
57 | */
58 | @Test
59 | public void setLevelTest() throws Exception {
60 | }
61 |
62 | /**
63 | *
64 | * Method: getTocTitle()
65 | */
66 | @Test
67 | public void getTocTitleTest() throws Exception {
68 | }
69 |
70 | /**
71 | *
72 | * Method: setTocTitle(tocTitle)
73 | */
74 | @Test
75 | public void setTocTitleTest() throws Exception {
76 | }
77 |
78 | /**
79 | *
80 | * Method: getTocHref()
81 | */
82 | @Test
83 | public void getTocHrefTest() throws Exception {
84 | }
85 |
86 | /**
87 | *
88 | * Method: setTocHref(tocHref)
89 | */
90 | @Test
91 | public void setTocHrefTest() throws Exception {
92 | }
93 |
94 | /**
95 | *
96 | * Method: getChildren()
97 | */
98 | @Test
99 | public void getChildrenTest() throws Exception {
100 | }
101 |
102 | /**
103 | *
104 | * Method: setChildren(children)
105 | */
106 | @Test
107 | public void setChildrenTest() throws Exception {
108 | }
109 |
110 | /**
111 | *
112 | * Method: getParent()
113 | */
114 | @Test
115 | public void getParentTest() throws Exception {
116 | }
117 |
118 | /**
119 | *
120 | * Method: setParent(parent)
121 | */
122 | @Test
123 | public void setParentTest() throws Exception {
124 | }
125 |
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/test/resources/CODE_BLOCK.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * 1 [符号场景测试](#符号场景测试)
4 | * 1.1 [场景 1](#场景-1)
5 | * 1.2 [场景 2](#场景-2)
6 | * 1.3 [场景 3](#场景-3)
7 | * 1.4 [场景 4](#场景-4)
8 | * 1.5 [场景 5](#场景-5)
9 | * 2 [空格的测试场景](#空格的测试场景)
10 | * 2.1 [代码块原则](#代码块原则)
11 | * 2.2 [场景 1](#场景-1-1)
12 | * 2.3 [场景 2](#场景-2-1)
13 | * 3 [混合使用](#混合使用)
14 | * 3.1 [场景 1](#场景-1-2)
15 | * 3.2 [场景 2](#场景-2-2)
16 |
17 |
18 | # 符号场景测试
19 |
20 | @since v1.0.7
21 |
22 | ## 场景 1
23 |
24 | ```
25 | # code...
26 | ```
27 |
28 | ## 场景 2
29 |
30 | ```c
31 | # code...
32 | ```
33 |
34 | ## 场景 3
35 |
36 | ```
37 | # code...
38 | ```c
39 | ```
40 |
41 | ## 场景 4
42 |
43 | ```c
44 | # code...
45 | ```c
46 | ```
47 |
48 | ## 场景 5
49 |
50 | ```c
51 | #三个空格```的测试
52 | ```
53 |
54 | # 空格的测试场景
55 |
56 | ## 代码块原则
57 |
58 | 上一行空行
59 |
60 | 本行:四个空格开头。
61 |
62 | ## 场景 1
63 |
64 | 第一行
65 |
66 | #第三行是代码
67 | 第四行
68 |
69 | ## 场景 2
70 |
71 | 第一行
72 | 第三行不是代码
73 | 第四行
74 |
75 | # 混合使用
76 |
77 | ## 场景 1
78 |
79 | ```c
80 | #第一行这是代码
81 | # 第二行这是代码
82 | ```
83 |
84 | ## 场景 2
85 |
86 | ```c
87 | 这不是代码,因为上面的一句被当成代码块处理了。
88 | ```
89 | ```c 代码块
90 | ```
91 |
--------------------------------------------------------------------------------
/src/test/resources/N-LEVEL.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [N 级深度测试](#n-级深度测试)
4 | * [1级别](#1级别)
5 | * [2 级别](#2-级别)
6 | * [3级别](#3级别)
7 | * [4级别](#4级别)
8 | * [5级别](#5级别)
9 | * [6级别](#6级别)
10 | * [一级别](#一级别)
11 | * [二级别](#二级别)
12 | * [三级别](#三级别)
13 | * [四级别](#四级别)
14 | * [五级别](#五级别)
15 | * [六级别](#六级别)
16 | * [一级别](#一级别-1)
17 | * [二级别](#二级别-1)
18 | * [三级别](#三级别-1)
19 | * [四级别](#四级别-1)
20 | * [五级别](#五级别-1)
21 | * [六级别](#六级别-1)
22 |
23 |
24 | # N 级深度测试
25 |
26 | # 1级别
27 | ## 2 级别
28 | ### 3级别
29 | #### 4级别
30 | ##### 5级别
31 | ###### 6级别
32 |
33 |
34 | # 一级别
35 | ## 二级别
36 | ### 三级别
37 | #### 四级别
38 | ##### 五级别
39 | ###### 六级别
40 |
41 | # 一级别
42 | ## 二级别
43 | ### 三级别
44 | #### 四级别
45 | ##### 五级别
46 | ###### 六级别
47 |
--------------------------------------------------------------------------------
/src/test/resources/README-GBK.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/README-GBK.md
--------------------------------------------------------------------------------
/src/test/resources/common.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [目录](#目录)
4 | * [二级](#二级)
5 | * [三级](#三级)
6 | * [第二个目录](#第二个目录)
7 | * [二级](#二级-1)
8 | * [三级](#三级-1)
9 |
10 |
11 | # 目录
12 |
13 | ## 二级
14 |
15 | ### 三级
16 |
17 | # 第二个目录
18 |
19 | ## 二级
20 |
21 | ### 三级
22 |
--------------------------------------------------------------------------------
/src/test/resources/empty-content.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [N 级深度测试](#n-级深度测试)
4 | * [1级别](#1级别)
5 | * [2 级别](#2-级别)
6 | * [3级别](#3级别)
7 | * [4级别](#4级别)
8 | * [5级别](#5级别)
9 | * [6级别](#6级别)
10 | * [一级别](#一级别)
11 | * [二级别](#二级别)
12 | * [三级别](#三级别)
13 | * [四级别](#四级别)
14 | * [五级别](#五级别)
15 | * [六级别](#六级别)
16 | * [一级别](#一级别-1)
17 | * [二级别](#二级别-1)
18 | * [三级别](#三级别-1)
19 | * [四级别](#四级别-1)
20 | * [五级别](#五级别-1)
21 | * [六级别](#六级别-1)
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/test/resources/empty.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/empty.md
--------------------------------------------------------------------------------
/src/test/resources/readme/README.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * 1 [markdown-toc](#markdown-toc)
4 | * 1.1 [变更日志](#变更日志)
5 | * 1.2 [Features](#features)
6 | * 2 [环境依赖](#环境依赖)
7 | * 2.1 [JDK](#jdk)
8 | * 2.2 [Maven](#maven)
9 | * 3 [快速入门](#快速入门)
10 | * 3.1 [maven 引入](#maven-引入)
11 | * 3.2 [md 文件](#md-文件)
12 | * 3.3 [快速开始](#快速开始)
13 | * 4 [属性配置](#属性配置)
14 | * 4.1 [属性说明](#属性说明)
15 | * 4.2 [返回值说明](#返回值说明)
16 | * 5 [测试案例](#测试案例)
17 | * 6 [其他](#其他)
18 |
19 |
20 | # markdown-toc
21 |
22 |
23 | ```
24 | _ __ ___ __ _ _ __| | ____| | _____ ___ __ | |_ ___ ___
25 | | '_ ` _ \ / _` | '__| |/ / _` |/ _ \ \ /\ / / '_ \ _____| __/ _ \ / __|
26 | | | | | | | (_| | | | < (_| | (_) \ V V /| | | |_____| || (_) | (__
27 | |_| |_| |_|\__,_|_| |_|\_\__,_|\___/ \_/\_/ |_| |_| \__\___/ \___|
28 |
29 | ```
30 |
31 | [](http://mvnrepository.com/artifact/com.github.houbb/markdown-toc)
32 | [](https://www.travis-ci.org/houbb/markdown-toc?branch=release_1.0.2)
33 | [](https://coveralls.io/github/houbb/markdown-toc?branch=release_1.0.2)
34 |
35 | Markdown-toc 可以用来生成 markdown 页面的目录,便于 github 页面展现。
36 |
37 |
38 | - 文档
39 |
40 | [中文说明](README.md) | [English Readme](README-ENGLISH.md)
41 |
42 | > 备注
43 |
44 | 对于标题,md 有两种语法 [setext](http://docutils.sourceforge.net/mirror/setext.html)
45 | 和 [atx](http://www.aaronsw.com/2002/atx/) 模式。
46 |
47 | 暂时只支持 **atx** 形式。
48 |
49 | ## 变更日志
50 |
51 | [变更日志](doc/changelog/CHANGELOG.md)
52 |
53 | ## Features
54 |
55 | - Github Markdown 文件一键生成目录
56 |
57 | - 支持 fluent 优雅的写法
58 |
59 | - 支持多次生成
60 |
61 | - 支持重复标题的生成
62 |
63 | - 支持特殊字符的过滤
64 |
65 | - 支持指定不同的文件编码
66 |
67 | - 支持文件夹的文件批量处理(可指定是否包含子文件夹文件)
68 |
69 | - 支持是否写入文件,可返回目录的内容,便于用户自行处理
70 |
71 | - 支持多线程写文件
72 |
73 | - 支持 i18n
74 |
75 | - 支持目录编号生成(1.0.5)
76 |
77 | # 环境依赖
78 |
79 | ## JDK
80 |
81 | JDK8+, 请确保 JDK 设置正确。
82 |
83 | ## Maven
84 |
85 | Jar 使用 [Maven](http://maven.apache.org/) 进行统一管理。
86 |
87 | # 快速入门
88 |
89 | ## maven 引入
90 |
91 | ```xml
92 |
93 | com.github.houbb
94 | markdown-toc
95 | ${maven-version}
96 |
97 | ```
98 |
99 | ## md 文件
100 |
101 | 本项目支持的 md 文件后缀名称为 `.md` 或者 `.markdown`
102 |
103 | ## 快速开始
104 |
105 | - 单个文件
106 |
107 | ```java
108 | AtxMarkdownToc.newInstance().genTocFile(path);
109 | ```
110 |
111 | 其中 path 为 md 文件的路径
112 |
113 | - 指定文件夹
114 |
115 | ```java
116 | AtxMarkdownToc.newInstance().genTocFile(path);
117 | ```
118 |
119 | 其中 path 为 md 文件的父类文件夹
120 |
121 | # 属性配置
122 |
123 | - 代码示例
124 |
125 | ```java
126 | AtxMarkdownToc.newInstance()
127 | .charset("UTF-8")
128 | .write(true)
129 | .subTree(true);
130 | ```
131 |
132 | ## 属性说明
133 |
134 | | 序号 | 属性 | 默认值 | 说明 |
135 | |:----|:----|:----|:----|
136 | | 1 | charset | `UTF-8` | 文件编码 |
137 | | 2 | write | `true` | 是否将 toc 写入文件(默认写入) |
138 | | 3 | subTree | `true` | 是否包含子文件夹的文件(默认包含) |
139 | | 4 | order | `false` | 是否生成目录编号(默认不生成,1.0.5以后) |
140 |
141 | ## 返回值说明
142 |
143 | `genTocFile()` 返回 TocGen,`genTocDir()` 返回 List
144 |
145 | - TocGen 属性说明
146 |
147 | | 序号 | 属性 | 类型 | 说明 |
148 | |:----|:----|:----| :----|
149 | | 1 | filePath | String | 当前 md 的文件路径 |
150 | | 2 | tocLines | List | 当前 md 文件对应的目录内容 |
151 |
152 | # 测试案例
153 |
154 | [单个文件-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java)
155 |
156 | [文件夹-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java)
157 |
158 | # 其他
159 |
160 | > [Issues & Bugs](https://github.com/houbb/markdown-toc/issues)
161 |
--------------------------------------------------------------------------------
/src/test/resources/special/chinese.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [中文标点:【】{}()!-=——+@#¥%……&*()——+、。,;‘“:、|、·~《》,。、?](#中文标点-)
4 |
5 |
6 | # 中文标点:【】{}()!-=——+@#¥%……&*()——+、。,;‘“:、|、·~《》,。、?
7 |
--------------------------------------------------------------------------------
/src/test/resources/special/emoji.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [笑臉與人物😀 😬 😁 😂 😃 😄 🤣 😅 😆 😇 😉 😊 🙂 🙃 ☺ 😋 😌 😍 😘 😗 😙 😚 🤪 😜 😝 😛 🤑 😎 🤓 🧐 🤠 🤗 🤡 😏 😶 😐 😑 😒 🙄 🤨 🤔 🤫 🤭 🤥 😳 😞 😟 😠 😡 🤬 😔 😕 🙁 ☹ 😣 😖 😫 😩 😤 😮 😱 😨 😰 😯 😦 😧 😢 😥 😪 🤤 😓 😭 🤩 😵 😲 🤯 🤐 😷 🤕 🤒 🤮 🤢 🤧 😴 💤 😈 👿 👹 👺 💩 👻 💀 ☠ 👽 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 👐 🤲 🙌 👏 🙏 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌ 🤘 🤟 👌 👈 👉 👆 👇 ☝ ✋ 🤚 🖐 🖖 👋 🤙 💪 🖕 ✍ 🤳 💅 👄 👅 👂 👃 👁 👀 🧠 👤 👥 🗣 👶 🧒 👦 👧 🧑 👨 🧔 👱♂️ 👩 👱♀️ 🧓 👴 👵 👲 👳♀️ 👳♂️ 🧕 👮♀️ 👮♂️ 👩🚒 👨🚒 👷♀️ 👷♂️ 👩🏭 👨🏭 👩🔧 👨🔧 👩🌾 👨🌾 👩🍳 👨🍳 👩🎤 👨🎤 👩🎨 👨🎨 👩🏫 👨🏫 👩🎓 👨🎓 👩💼 👨💼 👩💻 👨💻 👩🔬 👨🔬 👩🚀 👨🚀 👩⚕️ 👨⚕️ 👩⚖️ 👨⚖️ 👩✈️ 👨✈️ 💂♀️ 💂♂️ 🕵️♀️ 🕵️♂️ 🤶 🎅 👼 👸 🤴 👰 🤵♀️ 🤵 🕴️♀️ 🕴 🧙♀️ 🧙♂️ 🧝♀️ 🧝♂️ 🧚♀️ 🧚♂️ 🧞♀️ 🧞♂️ 🧜♀️ 🧜♂️ 🧛♀️ 🧛♂️ 🧟♀️ 🧟♂️ 🙇♀️ 🙇♂️ 💁♀️ 💁♂️ 🙅♀️ 🙅♂️ 🙆♀️ 🙆♂️ 🤷♀️ 🤷♂️ 🙋♀️ 🙋♂️ 🤦♀️ 🤦♂️ 🙎♀️ 🙎♂️ 🙍♀️ 🙍♂️ 💇♀️ 💇♂️ 💆♀️ 💆♂️ 🤰 🤱 🚶♀️ 🚶♂️ 🏃♀️ 🏃♂️ 💃 🕺 👯♀️ 👯♂️ 👫 👬 👭 💑 👩❤️👩 👨❤️👨 💏 👩❤️💋👩 👨❤️💋👨 👪 👨👩👧 👨👩👧👦 👨👩👦👦 👨👩👧👧 👩👩👦 👩👩👧 👩👩👧👦 👩👩👦👦 👩👩👧👧 👨👨👦 👨👨👧 👨👨👧👦 👨👨👦👦 👨👨👧👧 👩👦 👩👧 👩👧👦 👩👦👦 👩👧👧 👨👦 👨👧 👨👧👦 👨👦👦 👨👧👧 👚 👕 🧥 👖 👔 👗 👙 👘 💄 💋 👣 🧦 👠 👡 👢 👞 👟 🧢 👒 🎩 🎓 👑 ⛑ 🎒 👝 👛 👜 💼 👓 🕶 🧣 🧤 💍 🌂 ☂](#笑臉與人物-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------)
4 | * [動物與大自然](#動物與大自然)
5 | * [美食與飲料](#美食與飲料)
6 | * [运动 ⚽ 🏀 🏈 ⚾ 🎾 🏐 🏉 🎱 🏓 🏸 🥅 🏒 🏑 🏏 🥌 ⛳ 🏹 🎣 🥊 🥋 ⛸ 🎿 🛷 ⛷ 🏂 🏋️♀️ 🏋️♂️ 🤺 🤼♀️ 🤼♂️ 🤸♀️ 🤸♂️ ⛹️♀️ ⛹️♂️ 🤾♀️ 🤾♂️ 🧗♀️ 🧗♂️ 🏌️♀️ 🏌️♂️ 🧘♀️ 🧘♂️ 🧖♀️ 🧖♂️ 🏄♀️ 🏄♂️ 🏊♀️ 🏊♂️ 🤽♀️ 🤽♂️ 🚣♀️ 🚣♂️ 🏇 🚴♀️ 🚴♂️ 🚵♀️ 🚵♂️ 🎽 🎖 🏅 🥇 🥈 🥉 🏆 🏵 🎗 🎫 🎟 🎪 🤹♀️ 🤹♂️ 🎭 🎨 🎬 🎤 🎧 🎼 🎹 🥁 🎷 🎺 🎸 🎻 🎲 🎯 🎳 🎮 👾 🎰](#运动-----------------------------------------------------------------------------------------)
7 | * [旅游🚗 🚕 🚙 🚌 🚎 🏎 🚓 🚑 🚒 🚐 🚚 🚛 🚜 🏍 🛵 🚲 🛴 🚨 🚔 🚍 🚘 🚖 🚡 🚠 🚟 🚃 🚋 🚝 🚄 🚅 🚈 🚞 🚂 🚆 🚇 🚊 🚉 🚁 🛩 ✈ 🛫 🛬 🛶 ⛵ 🛥 🚤 ⛴ 🛳 🚀 🛸 🛰 💺 ⚓ 🚧 ⛽ 🚏 🚦 🚥 🛑 🚢 🎡 🎢 🎠 🏗 🌁 🗼 🏭 ⛲ 🎑 ⛰ 🏔 🗻 🌋 🗾 🏕 ⛺ 🏞 🛣 🛤 🌅 🌄 🏜 🏖 🏝 🌇 🌆 🏙 🌃 🌉 🌌 🌠 🎇 🎆 🌈 🏘 🏰 🏯 🏟 🗽 🏠 🏡 🏚 🏢 🏬 🏣 🏤 🏥 🏦 🏨 🏪 🏫 🏩 💒 🏛 ⛪ 🕌 🕍 🕋 ⛩](#旅游----------------------------------------------------------------------------------------------------------------------)
8 | * [物品 ⌚ 📱 📲 💻 ⌨ 🖥 🖨 🖱 🖲 🕹 🗜 💽 💾 💿 📀 📼 📷 📸 📹 🎥 📽 🎞 📞 ☎ 📟 📠 📺 📻 🎙 🎚 🎛 ⏱ ⏲ ⏰ 🕰 ⏳ ⌛ 📡 🔋 🔌 💡 🔦 🕯 🗑 🛢 🛒 💸 💵 💴 💶 💷 💰 💳 💎 ⚖ 🔧 🔨 ⚒ 🛠 ⛏ 🔩 ⚙ ⛓ 🔫 💣 🔪 🗡 ⚔ 🛡 🚬 ⚰ ⚱ 🏺 🔮 📿 💈 ⚗ 🔭 🔬 🕳 💊 💉 🌡 🏷 🔖 🚽 🚿 🛁 🛀 🔑 🗝 🛋 🛌 🛏 🚪 🛎 🖼 🗺 ⛱ 🗿 🛍 🎈 🎏 🎀 🎁 🎊 🎉 🎎 🎐 🏮 ✉ 📩 📨 📧 💌 📮 📪 📫 📬 📭 📦 📯 📥 📤 📜 📃 📑 📊 📈 📉 📄 📅 📆 🗓 📇 🗃 🗳 🗄 📋 🗒 📁 📂 🗂 🗞 📰 📓 📕 📗 📘 📙 📔 📒 📚 📖 🔗 📎 🖇 ✂ 📐 📏 📌 📍 🔐 🔒 🔓 🔏 🖊 🖋 ✒ 📝 ✏ 🖍 🖌 🔍 🔎](#物品-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------)
9 | * [符號❤ 🧡 💛 💚 💙 💜 🖤 💔 ❣ 💕 💞 💓 💗 💖 💘 💝 💟 ☮ ✝ ☪ 🕉 ☸ ✡ 🔯 🕎 ☯ ☦ 🛐 ⛎ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ 🆔 ⚛ ⚕ ☢ ☣ 📴 📳 🈶 🈚 🈸 🈺 🈷 ✴ 🆚 🉑 💮 🉐 ㊙ ㊗ 🈴 🈵 🈹 🈲 🅰 🅱 🆎 🆑 🅾 🆘 ⛔ 📛 🚫 ❌ ⭕ 💢 ♨ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗ ❕ ❓ ❔ ‼ ⁉ 💯 🔅 🔆 🔱 ⚜ 〽 ⚠ 🚸 🔰 ♻ 🈯 💹 ❇ ✳ ❎ ✅ 💠 🌀 ➿ 🌐 Ⓜ 🏧 🚾 ♿ 🅿 🈳 🈂 🛂 🛃 🛄 🛅 🚰 🚹 ♂ 🚺 ♀ 🚼 🚻 🚮 🎦 📶 🈁 🆖 🆗 🆙 🆒 🆕 🆓 0⃣ 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 | # 符號❤ 🧡 💛 💚 💙 💜 🖤 💔 ❣ 💕 💞 💓 💗 💖 💘 💝 💟 ☮ ✝ ☪ 🕉 ☸ ✡ 🔯 🕎 ☯ ☦ 🛐 ⛎ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ 🆔 ⚛ ⚕ ☢ ☣ 📴 📳 🈶 🈚 🈸 🈺 🈷 ✴ 🆚 🉑 💮 🉐 ㊙ ㊗ 🈴 🈵 🈹 🈲 🅰 🅱 🆎 🆑 🅾 🆘 ⛔ 📛 🚫 ❌ ⭕ 💢 ♨ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗ ❕ ❓ ❔ ‼ ⁉ 💯 🔅 🔆 🔱 ⚜ 〽 ⚠ 🚸 🔰 ♻ 🈯 💹 ❇ ✳ ❎ ✅ 💠 🌀 ➿ 🌐 Ⓜ 🏧 🚾 ♿ 🅿 🈳 🈂 🛂 🛃 🛄 🛅 🚰 🚹 ♂ 🚺 ♀ 🚼 🚻 🚮 🎦 📶 🈁 🆖 🆗 🆙 🆒 🆕 🆓 0⃣ 1⃣ 2⃣ 3⃣ 4⃣ 5⃣ 6⃣ 7⃣ 8⃣ 9⃣ 🔟 🔢 ▶ ⏸ ⏯ ⏹ ⏺ ⏏ ⏭ ⏮ ⏩ ⏪ 🔀 🔁 🔂 ◀ 🔼 🔽 ⏫ ⏬ ➡ ⬅ ⬆ ⬇ ↗ ↘ ↙ ↖ ↕ ↔ 🔄 ↪ ↩ 🔃 ⤴ ⤵ #⃣ *⃣ ℹ 🔤 🔡 🔠 🔣 🎵 🎶 〰 ➰ ✔ ➕ ➖ ➗ ✖ 💲 💱 🔚 🔙 🔛 🔝 🔜 ☑ 🔘 ⚪ ⚫ 🔴 🔵 🔸 🔹 🔶 🔷 🔺 ▪ ▫ ⬛ ⬜ 🔻 ◼ ◻ ◾ ◽ 🔲 🔳 🔈 🔉 🔊 🔇 📣 📢 🔔 🔕 🃏 🀄 ♠ ♣ ♥ ♦ 🎴 👁🗨 🗨 💭 🗯 💬 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 🕟 🕠 🕡 🕢 🕣 🕤 🕥 🕦 🕧
30 |
31 | # 旗帜 🏳️ 🏴 🏁 🚩 🏳️🌈 🏴☠️ 🇦🇫 🇦🇽 🇦🇱 🇩🇿 🇦🇸 🇦🇩 🇦🇴 🇦🇮 🇦🇶 🇦🇬 🇦🇷 🇦🇲 🇦🇼 🇦🇺 🇦🇹 🇦🇿 🇧🇸 🇧🇭 🇧🇩 🇧🇧 🇧🇾 🇧🇪 🇧🇿 🇧🇯 🇧🇲 🇧🇹 🇧🇴 🇧🇦 🇧🇼 🇧🇷 🇮🇴 🇻🇬 🇧🇳 🇧🇬 🇧🇫 🇧🇮 🇰🇭 🇨🇲 🇨🇦 🇮🇨 🇨🇻 🇧🇶 🇰🇾 🇨🇫 🇹🇩 🇨🇱 🇨🇳 🇨🇽 🇨🇨 🇨🇴 🇰🇲 🇨🇬 🇨🇩 🇨🇰 🇨🇷 🇨🇮 🇭🇷 🇨🇺 🇨🇼 🇨🇾 🇨🇿 🇩🇰 🇩🇯 🇩🇲 🇩🇴 🇪🇨 🇪🇬 🇸🇻 🇬🇶 🇪🇷 🇪🇪 🇪🇹 🇪🇺 🇫🇰 🇫🇴 🇫🇯 🇫🇮 🇫🇷 🇬🇫 🇵🇫 🇹🇫 🇬🇦 🇬🇲 🇬🇪 🇩🇪 🇬🇭 🇬🇮 🇬🇷 🇬🇱 🇬🇩 🇬🇵 🇬🇺 🇬🇹 🇬🇬 🇬🇳 🇬🇼 🇬🇾 🇭🇹 🇭🇳 🇭🇰 🇭🇺 🇮🇸 🇮🇳 🇮🇩 🇮🇷 🇮🇶 🇮🇪 🇮🇲 🇮🇱 🇮🇹 🇯🇲 🇯🇵 🎌 🇯🇪 🇯🇴 🇰🇿 🇰🇪 🇰🇮 🇽🇰 🇰🇼 🇰🇬 🇱🇦 🇱🇻 🇱🇧 🇱🇸 🇱🇷 🇱🇾 🇱🇮 🇱🇹 🇱🇺 🇲🇴 🇲🇰 🇲🇬 🇲🇼 🇲🇾 🇲🇻 🇲🇱 🇲🇹 🇲🇭 🇲🇶 🇲🇷 🇲🇺 🇾🇹 🇲🇽 🇫🇲 🇲🇩 🇲🇨 🇲🇳 🇲🇪 🇲🇸 🇲🇦 🇲🇿 🇲🇲 🇳🇦 🇳🇷 🇳🇵 🇳🇱 🇳🇨 🇳🇿 🇳🇮 🇳🇪 🇳🇬 🇳🇺 🇳🇫 🇰🇵 🇲🇵 🇳🇴 🇴🇲 🇵🇰 🇵🇼 🇵🇸 🇵🇦 🇵🇬 🇵🇾 🇵🇪 🇵🇭 🇵🇳 🇵🇱 🇵🇹 🇵🇷 🇶🇦 🇷🇪 🇷🇴 🇷🇺 🇷🇼 🇼🇸 🇸🇲 🇸🇦 🇸🇳 🇷🇸 🇸🇨 🇸🇱 🇸🇬 🇸🇽 🇸🇰 🇸🇮 🇬🇸 🇸🇧 🇸🇴 🇿🇦 🇰🇷 🇸🇸 🇪🇸 🇱🇰 🇧🇱 🇸🇭 🇰🇳 🇱🇨 🇵🇲 🇻🇨 🇸🇩 🇸🇷 🇸🇿 🇸🇪 🇨🇭 🇸🇾 🇹🇼 🇹🇯 🇹🇿 🇹🇭 🇹🇱 🇹🇬 🇹🇰 🇹🇴 🇹🇹 🇹🇳 🇹🇷 🇹🇲 🇹🇨 🇹🇻 🇻🇮 🇺🇬 🇺🇦 🇦🇪 🇬🇧 🏴 🏴 🏴 🇺🇸 🇺🇾 🇺🇿 🇻🇺 🇻🇦 🇻🇪 🇻🇳 🇼🇫 🇪🇭 🇾🇪 🇿🇲 🇿🇼
32 |
--------------------------------------------------------------------------------
/src/test/resources/special/special.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [英文標點:`~!@#$%^&*()_+-=[]{}\|"';:/.,.<>/?](#英文標點_-)
4 | * [ILOVEMD∂ILOVEMD](#ilovemdilovemd)
5 | * [ILOVEMD∏ILOVEMD](#ilovemdilovemd-1)
6 | * [ILOVEMD←ILOVEMD](#ilovemdilovemd-2)
7 | * [ILOVEMD∑ILOVEMD](#ilovemdilovemd-3)
8 | * [ILOVEMD↑ILOVEMD](#ilovemdilovemd-4)
9 | * [ILOVEMD−ILOVEMD](#ilovemdilovemd-5)
10 | * [ILOVEMD→ILOVEMD](#ilovemdilovemd-6)
11 | * [ILOVEMD↓ILOVEMD](#ilovemdilovemd-7)
12 | * [ILOVEMD–ILOVEMD](#ilovemdilovemd-8)
13 | * [ILOVEMD↔ILOVEMD](#ilovemdilovemd-9)
14 | * [ILOVEMD—ILOVEMD](#ilovemdilovemd-10)
15 | * [ILOVEMD‘ILOVEMD](#ilovemdilovemd-11)
16 | * [ILOVEMD’ILOVEMD](#ilovemdilovemd-12)
17 | * [ILOVEMD‚ILOVEMD](#ilovemdilovemd-13)
18 | * [ILOVEMD√ILOVEMD](#ilovemdilovemd-14)
19 | * [ILOVEMD“ILOVEMD](#ilovemdilovemd-15)
20 | * [ILOVEMD”ILOVEMD](#ilovemdilovemd-16)
21 | * [ILOVEMD„ILOVEMD](#ilovemdilovemd-17)
22 | * [ILOVEMD∞ILOVEMD](#ilovemdilovemd-18)
23 | * [ILOVEMD†ILOVEMD](#ilovemdilovemd-19)
24 | * [ILOVEMD!ILOVEMD](#ilovemdilovemd-20)
25 | * [ILOVEMD‡ILOVEMD](#ilovemdilovemd-21)
26 | * [ILOVEMD¡ILOVEMD](#ilovemdilovemd-22)
27 | * [ILOVEMD"ILOVEMD](#ilovemdilovemd-23)
28 | * [ILOVEMD™ILOVEMD](#ilovemdilovemd-24)
29 | * [ILOVEMD•ILOVEMD](#ilovemdilovemd-25)
30 | * [ILOVEMD¢ILOVEMD](#ilovemdilovemd-26)
31 | * [ILOVEMD#ILOVEMD](#ilovemdilovemd-27)
32 | * [ILOVEMD£ILOVEMD](#ilovemdilovemd-28)
33 | * [ILOVEMD$ILOVEMD](#ilovemdilovemd-29)
34 | * [ILOVEMD%ILOVEMD](#ilovemdilovemd-30)
35 | * [ILOVEMD¥ILOVEMD](#ilovemdilovemd-31)
36 | * [ILOVEMD&ILOVEMD](#ilovemdilovemd-32)
37 | * [ILOVEMD¦ILOVEMD](#ilovemdilovemd-33)
38 | * [ILOVEMD…ILOVEMD](#ilovemdilovemd-34)
39 | * [ILOVEMD'ILOVEMD](#ilovemdilovemd-35)
40 | * [ILOVEMD§ILOVEMD](#ilovemdilovemd-36)
41 | * [ILOVEMD(ILOVEMD](#ilovemdilovemd-37)
42 | * [ILOVEMD¨ILOVEMD](#ilovemdilovemd-38)
43 | * [ILOVEMD)ILOVEMD](#ilovemdilovemd-39)
44 | * [ILOVEMD©ILOVEMD](#ilovemdilovemd-40)
45 | * [ILOVEMD∩ILOVEMD](#ilovemdilovemd-41)
46 | * [ILOVEMD*ILOVEMD](#ilovemdilovemd-42)
47 | * [ILOVEMD+ILOVEMD](#ilovemdilovemd-43)
48 | * [ILOVEMD∫ILOVEMD](#ilovemdilovemd-44)
49 | * [ILOVEMD«ILOVEMD](#ilovemdilovemd-45)
50 | * [ILOVEMD,ILOVEMD](#ilovemdilovemd-46)
51 | * [ILOVEMD€ILOVEMD](#ilovemdilovemd-47)
52 | * [ILOVEMD¬ILOVEMD](#ilovemdilovemd-48)
53 | * [ILOVEMD.ILOVEMD](#ilovemdilovemd-49)
54 | * [ILOVEMD®ILOVEMD](#ilovemdilovemd-50)
55 | * [ILOVEMD/ILOVEMD](#ilovemdilovemd-51)
56 | * [ILOVEMD¯ILOVEMD](#ilovemdilovemd-52)
57 | * [ILOVEMD°ILOVEMD](#ilovemdilovemd-53)
58 | * [ILOVEMD‰ILOVEMD](#ilovemdilovemd-54)
59 | * [ILOVEMD±ILOVEMD](#ilovemdilovemd-55)
60 | * [ILOVEMD′ILOVEMD](#ilovemdilovemd-56)
61 | * [ILOVEMD″ILOVEMD](#ilovemdilovemd-57)
62 | * [ILOVEMD´ILOVEMD](#ilovemdilovemd-58)
63 | * [ILOVEMD¶ILOVEMD](#ilovemdilovemd-59)
64 | * [ILOVEMD·ILOVEMD](#ilovemdilovemd-60)
65 | * [ILOVEMD¸ILOVEMD](#ilovemdilovemd-61)
66 | * [ILOVEMD‹ILOVEMD](#ilovemdilovemd-62)
67 | * [ILOVEMD:ILOVEMD](#ilovemdilovemd-63)
68 | * [ILOVEMD›ILOVEMD](#ilovemdilovemd-64)
69 | * [ILOVEMD;ILOVEMD](#ilovemdilovemd-65)
70 | * [ILOVEMD»ILOVEMD](#ilovemdilovemd-66)
71 | * [ILOVEMD¼ILOVEMD](#ilovemdilovemd-67)
72 | * [ILOVEMDILOVEMD](#ilovemdilovemd-72)
77 | * [ILOVEMD‾ILOVEMD](#ilovemdilovemd-73)
78 | * [ILOVEMD?ILOVEMD](#ilovemdilovemd-74)
79 | * [ILOVEMD¿ILOVEMD](#ilovemdilovemd-75)
80 | * [ILOVEMD@ILOVEMD](#ilovemdilovemd-76)
81 | * [ILOVEMD⁄ILOVEMD](#ilovemdilovemd-77)
82 | * [ILOVEMD≈ILOVEMD](#ilovemdilovemd-78)
83 | * [ILOVEMD◊ILOVEMD](#ilovemdilovemd-79)
84 | * [ILOVEMD×ILOVEMD](#ilovemdilovemd-80)
85 | * [ILOVEMD\ILOVEMD](#ilovemdilovemd-81)
86 | * [ILOVEMD˜ILOVEMD](#ilovemdilovemd-82)
87 | * [ILOVEMD^ILOVEMD](#ilovemdilovemd-83)
88 | * [ILOVEMD≠ILOVEMD](#ilovemdilovemd-84)
89 | * [ILOVEMD♠ILOVEMD](#ilovemdilovemd-85)
90 | * [ILOVEMD≡ILOVEMD](#ilovemdilovemd-86)
91 | * [ILOVEMD♣ILOVEMD](#ilovemdilovemd-87)
92 | * [ILOVEMD≤ILOVEMD](#ilovemdilovemd-88)
93 | * [ILOVEMD≥ILOVEMD](#ilovemdilovemd-89)
94 | * [ILOVEMD♥ILOVEMD](#ilovemdilovemd-90)
95 | * [ILOVEMD♦ILOVEMD](#ilovemdilovemd-91)
96 | * [ILOVEMD÷ILOVEMD](#ilovemdilovemd-92)
97 | * [ILOVEMD|ILOVEMD](#ilovemdilovemd-93)
98 | * [ILOVEMD~ILOVEMD](#ilovemdilovemd-94)
99 |
100 |
101 | # 英文標點:`~!@#$%^&*()_+-=[]{}\|"';:/.,.<>/?
102 |
103 | # ILOVEMD∂ILOVEMD
104 | ILOVEMD∂ILOVEMD
105 |
106 | # ILOVEMD∏ILOVEMD
107 | ILOVEMD∏ILOVEMD
108 |
109 | # ILOVEMD←ILOVEMD
110 | ILOVEMD←ILOVEMD
111 |
112 | # ILOVEMD∑ILOVEMD
113 | ILOVEMD∑ILOVEMD
114 |
115 | # ILOVEMD↑ILOVEMD
116 | ILOVEMD↑ILOVEMD
117 |
118 | # ILOVEMD−ILOVEMD
119 | ILOVEMD−ILOVEMD
120 |
121 | # ILOVEMD→ILOVEMD
122 | ILOVEMD→ILOVEMD
123 |
124 | # ILOVEMD↓ILOVEMD
125 | ILOVEMD↓ILOVEMD
126 |
127 | # ILOVEMD–ILOVEMD
128 | ILOVEMD–ILOVEMD
129 |
130 | # ILOVEMD↔ILOVEMD
131 | ILOVEMD↔ILOVEMD
132 |
133 | # ILOVEMD—ILOVEMD
134 | ILOVEMD—ILOVEMD
135 |
136 | # ILOVEMD‘ILOVEMD
137 | ILOVEMD‘ILOVEMD
138 |
139 | # ILOVEMD’ILOVEMD
140 | ILOVEMD’ILOVEMD
141 |
142 | # ILOVEMD‚ILOVEMD
143 | ILOVEMD‚ILOVEMD
144 |
145 | # ILOVEMD√ILOVEMD
146 | ILOVEMD√ILOVEMD
147 |
148 | # ILOVEMD“ILOVEMD
149 | ILOVEMD“ILOVEMD
150 |
151 | # ILOVEMD”ILOVEMD
152 | ILOVEMD”ILOVEMD
153 |
154 | # ILOVEMD„ILOVEMD
155 | ILOVEMD„ILOVEMD
156 |
157 | # ILOVEMD∞ILOVEMD
158 | ILOVEMD∞ILOVEMD
159 |
160 | # ILOVEMD†ILOVEMD
161 | ILOVEMD†ILOVEMD
162 |
163 | # ILOVEMD!ILOVEMD
164 | ILOVEMD!ILOVEMD
165 |
166 | # ILOVEMD‡ILOVEMD
167 | ILOVEMD‡ILOVEMD
168 |
169 | # ILOVEMD¡ILOVEMD
170 | ILOVEMD¡ILOVEMD
171 |
172 | # ILOVEMD"ILOVEMD
173 | ILOVEMD"ILOVEMD
174 |
175 | # ILOVEMD™ILOVEMD
176 | ILOVEMD™ILOVEMD
177 |
178 | # ILOVEMD•ILOVEMD
179 | ILOVEMD•ILOVEMD
180 |
181 | # ILOVEMD¢ILOVEMD
182 | ILOVEMD¢ILOVEMD
183 |
184 | # ILOVEMD#ILOVEMD
185 | ILOVEMD#ILOVEMD
186 |
187 | # ILOVEMD£ILOVEMD
188 | ILOVEMD£ILOVEMD
189 |
190 | # ILOVEMD$ILOVEMD
191 | ILOVEMD$ILOVEMD
192 |
193 | # ILOVEMD%ILOVEMD
194 | ILOVEMD%ILOVEMD
195 |
196 | # ILOVEMD¥ILOVEMD
197 | ILOVEMD¥ILOVEMD
198 |
199 | # ILOVEMD&ILOVEMD
200 | ILOVEMD&ILOVEMD
201 |
202 | # ILOVEMD¦ILOVEMD
203 | ILOVEMD¦ILOVEMD
204 |
205 | # ILOVEMD…ILOVEMD
206 | ILOVEMD…ILOVEMD
207 |
208 | # ILOVEMD'ILOVEMD
209 | ILOVEMD'ILOVEMD
210 |
211 | # ILOVEMD§ILOVEMD
212 | ILOVEMD§ILOVEMD
213 |
214 | # ILOVEMD(ILOVEMD
215 | ILOVEMD(ILOVEMD
216 |
217 | # ILOVEMD¨ILOVEMD
218 | ILOVEMD¨ILOVEMD
219 |
220 | # ILOVEMD)ILOVEMD
221 | ILOVEMD)ILOVEMD
222 |
223 | # ILOVEMD©ILOVEMD
224 | ILOVEMD©ILOVEMD
225 |
226 | # ILOVEMD∩ILOVEMD
227 | ILOVEMD∩ILOVEMD
228 |
229 | # ILOVEMD*ILOVEMD
230 | ILOVEMD*ILOVEMD
231 |
232 | # ILOVEMD+ILOVEMD
233 | ILOVEMD+ILOVEMD
234 |
235 | # ILOVEMD∫ILOVEMD
236 | ILOVEMD∫ILOVEMD
237 |
238 | # ILOVEMD«ILOVEMD
239 | ILOVEMD«ILOVEMD
240 |
241 | # ILOVEMD,ILOVEMD
242 | ILOVEMD,ILOVEMD
243 |
244 | # ILOVEMD€ILOVEMD
245 | ILOVEMD€ILOVEMD
246 |
247 | # ILOVEMD¬ILOVEMD
248 | ILOVEMD¬ILOVEMD
249 |
250 | # ILOVEMD.ILOVEMD
251 | ILOVEMD.ILOVEMD
252 |
253 | # ILOVEMD®ILOVEMD
254 | ILOVEMD®ILOVEMD
255 |
256 | # ILOVEMD/ILOVEMD
257 | ILOVEMD/ILOVEMD
258 |
259 | # ILOVEMD¯ILOVEMD
260 | ILOVEMD¯ILOVEMD
261 |
262 | # ILOVEMD°ILOVEMD
263 | ILOVEMD°ILOVEMD
264 |
265 | # ILOVEMD‰ILOVEMD
266 | ILOVEMD‰ILOVEMD
267 |
268 | # ILOVEMD±ILOVEMD
269 | ILOVEMD±ILOVEMD
270 |
271 | # ILOVEMD′ILOVEMD
272 | ILOVEMD′ILOVEMD
273 |
274 | # ILOVEMD″ILOVEMD
275 | ILOVEMD″ILOVEMD
276 |
277 | # ILOVEMD´ILOVEMD
278 | ILOVEMD´ILOVEMD
279 |
280 | # ILOVEMD¶ILOVEMD
281 | ILOVEMD¶ILOVEMD
282 |
283 | # ILOVEMD·ILOVEMD
284 | ILOVEMD·ILOVEMD
285 |
286 | # ILOVEMD¸ILOVEMD
287 | ILOVEMD¸ILOVEMD
288 |
289 | # ILOVEMD‹ILOVEMD
290 | ILOVEMD‹ILOVEMD
291 |
292 | # ILOVEMD:ILOVEMD
293 | ILOVEMD:ILOVEMD
294 |
295 | # ILOVEMD›ILOVEMD
296 | ILOVEMD›ILOVEMD
297 |
298 | # ILOVEMD;ILOVEMD
299 | ILOVEMD;ILOVEMD
300 |
301 | # ILOVEMD»ILOVEMD
302 | ILOVEMD»ILOVEMD
303 |
304 | # ILOVEMD¼ILOVEMD
305 | ILOVEMD¼ILOVEMD
306 |
307 | # ILOVEMDILOVEMD
320 | ILOVEMD>ILOVEMD
321 |
322 | # ILOVEMD‾ILOVEMD
323 | ILOVEMD‾ILOVEMD
324 |
325 | # ILOVEMD?ILOVEMD
326 | ILOVEMD?ILOVEMD
327 |
328 | # ILOVEMD¿ILOVEMD
329 | ILOVEMD¿ILOVEMD
330 |
331 | # ILOVEMD@ILOVEMD
332 | ILOVEMD@ILOVEMD
333 |
334 | # ILOVEMD⁄ILOVEMD
335 | ILOVEMD⁄ILOVEMD
336 |
337 | # ILOVEMD≈ILOVEMD
338 | ILOVEMD≈ILOVEMD
339 |
340 | # ILOVEMD◊ILOVEMD
341 | ILOVEMD◊ILOVEMD
342 |
343 | # ILOVEMD×ILOVEMD
344 | ILOVEMD×ILOVEMD
345 |
346 | # ILOVEMD\ILOVEMD
347 | ILOVEMD\ILOVEMD
348 |
349 | # ILOVEMD˜ILOVEMD
350 | ILOVEMD˜ILOVEMD
351 |
352 | # ILOVEMD^ILOVEMD
353 | ILOVEMD^ILOVEMD
354 |
355 | # ILOVEMD≠ILOVEMD
356 | ILOVEMD≠ILOVEMD
357 |
358 | # ILOVEMD♠ILOVEMD
359 | ILOVEMD♠ILOVEMD
360 |
361 | # ILOVEMD≡ILOVEMD
362 | ILOVEMD≡ILOVEMD
363 |
364 | # ILOVEMD♣ILOVEMD
365 | ILOVEMD♣ILOVEMD
366 |
367 | # ILOVEMD≤ILOVEMD
368 | ILOVEMD≤ILOVEMD
369 |
370 | # ILOVEMD≥ILOVEMD
371 | ILOVEMD≥ILOVEMD
372 |
373 | # ILOVEMD♥ILOVEMD
374 | ILOVEMD♥ILOVEMD
375 |
376 | # ILOVEMD♦ILOVEMD
377 | ILOVEMD♦ILOVEMD
378 |
379 | # ILOVEMD÷ILOVEMD
380 | ILOVEMD÷ILOVEMD
381 |
382 | # ILOVEMD|ILOVEMD
383 | ILOVEMD|ILOVEMD
384 |
385 | # ILOVEMD~ILOVEMD
386 | ILOVEMD~ILOVEMD
387 |
--------------------------------------------------------------------------------
/src/test/resources/sub/001.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [爱与正义](#爱与正义)
4 | * [爱河菠萝](#爱河菠萝)
5 | * [你的过去](#你的过去)
6 | * [散散是谁](#散散是谁)
7 | * [散散是谁](#散散是谁-1)
8 | * [001](#001)
9 |
10 |
11 | # 爱与正义
12 |
13 | ## 爱河菠萝
14 |
15 | ## 你的过去
16 |
17 | ## 散散是谁
18 |
19 | ## 散散是谁
20 |
21 | # 001
22 |
--------------------------------------------------------------------------------
/src/test/resources/sub/002.markdown:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [002](#002)
4 | * [爱与正义](#爱与正义)
5 | * [爱河菠萝](#爱河菠萝)
6 | * [你的过去](#你的过去)
7 | * [散散是谁](#散散是谁)
8 | * [爱与正义](#爱与正义-1)
9 | * [爱河菠萝](#爱河菠萝-1)
10 | * [你的过去](#你的过去-1)
11 | * [散散是谁](#散散是谁-1)
12 |
13 |
14 | # 002
15 |
16 | # 爱与正义
17 |
18 | ## 爱河菠萝
19 |
20 | ## 你的过去
21 |
22 | ## 散散是谁
23 |
24 | # 爱与正义
25 |
26 | ## 爱河菠萝
27 |
28 | ## 你的过去
29 |
30 | ## 散散是谁
31 |
--------------------------------------------------------------------------------
/src/test/resources/sub/003.text:
--------------------------------------------------------------------------------
1 | # 爱与正义
2 |
3 | ## 爱河菠萝
4 |
5 | # 爱与正义
6 |
7 | ## 爱河菠萝
8 |
9 | ## 你的过去
10 |
11 | ## 散散是谁
12 |
13 | # 爱与正义
14 |
15 | ## 爱河菠萝
16 |
17 | ## 你的过去
18 |
19 | ## 散散是谁
--------------------------------------------------------------------------------
/src/test/resources/sub/little/003.text:
--------------------------------------------------------------------------------
1 | # 爱与正义
2 |
3 | ## 爱河菠萝
4 |
5 | # 爱与正义
6 |
7 | ## 爱河菠萝
8 |
9 | ## 你的过去
10 |
11 | ## 散散是谁
12 |
13 | # 爱与正义
14 |
15 | ## 爱河菠萝
16 |
17 | ## 你的过去
18 |
19 | ## 散散是谁
--------------------------------------------------------------------------------
/src/test/resources/sub/little/008.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [008](#008)
4 | * [爱与正义](#爱与正义)
5 | * [爱河菠萝](#爱河菠萝)
6 | * [你的过去](#你的过去)
7 | * [散散是谁](#散散是谁)
8 |
9 |
10 | # 008
11 |
12 | # 爱与正义
13 |
14 | ## 爱河菠萝
15 |
16 | ## 你的过去
17 |
18 | ## 散散是谁
19 |
--------------------------------------------------------------------------------
/src/test/resources/sub/little/009.markdown:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [009](#009)
4 | * [爱与正义](#爱与正义)
5 | * [爱河菠萝](#爱河菠萝)
6 | * [你的过去](#你的过去)
7 | * [散散是谁](#散散是谁)
8 | * [爱与正义](#爱与正义-1)
9 | * [爱河菠萝](#爱河菠萝-1)
10 | * [你的过去](#你的过去-1)
11 | * [散散是谁](#散散是谁-1)
12 |
13 |
14 | # 009
15 |
16 | # 爱与正义
17 |
18 | ## 爱河菠萝
19 |
20 | ## 你的过去
21 |
22 | ## 散散是谁
23 |
24 | # 爱与正义
25 |
26 | ## 爱河菠萝
27 |
28 | ## 你的过去
29 |
30 | ## 散散是谁
31 |
--------------------------------------------------------------------------------
/src/test/resources/sub/sub/003.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [003](#003)
4 | * [爱与正义](#爱与正义)
5 | * [爱河菠萝](#爱河菠萝)
6 | * [你的过去](#你的过去)
7 | * [散散是谁](#散散是谁)
8 |
9 |
10 | # 003
11 |
12 | # 爱与正义
13 |
14 | ## 爱河菠萝
15 |
16 | ## 你的过去
17 |
18 | ## 散散是谁
19 |
--------------------------------------------------------------------------------
/src/test/resources/sub/sub/004.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [004](#004)
4 | * [爱与正义](#爱与正义)
5 | * [爱河菠萝](#爱河菠萝)
6 | * [你的过去](#你的过去)
7 | * [散散是谁](#散散是谁)
8 |
9 |
10 | # 004
11 |
12 | # 爱与正义
13 |
14 | ## 爱河菠萝
15 |
16 | ## 你的过去
17 |
18 | ## 散散是谁
19 |
--------------------------------------------------------------------------------
/src/test/resources/sub0/1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/sub0/1.txt
--------------------------------------------------------------------------------
/src/test/resources/sub1/1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/sub1/1.txt
--------------------------------------------------------------------------------
/src/test/resources/sub1/common.md:
--------------------------------------------------------------------------------
1 | # only one
2 |
3 | ## 只有一个文件哦
4 |
5 | ## 哈哈哈
6 |
--------------------------------------------------------------------------------
/src/test/resources/中文名称.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 |
3 | * [Table of Contents](#table-of-contents)
4 | * [Table of Contents](#table-of-contents-1)
5 | * [Paradise](#paradise)
6 | * [paradise-common](#paradise-common)
7 | * [paradise-enhance](#paradise-enhance)
8 | * [paradise-core](#paradise-core)
9 | * [paradise-test](#paradise-test)
10 | * [变更日志](#变更日志)
11 |
12 |
13 | # Table of Contents
14 |
15 | * [Paradise](#paradise)
16 | * [paradise-common](#paradise-common)
17 | * [paradise-enhance](#paradise-enhance)
18 | * [paradise-core](#paradise-core)
19 | * [paradise-test](#paradise-test)
20 | * [变更日志](#变更日志)
21 |
22 |
23 | # Table of Contents
24 |
25 | * [Paradise](#paradise)
26 | * [paradise-common](#paradise-common)
27 | * [paradise-enhance](#paradise-enhance)
28 | * [paradise-core](#paradise-core)
29 | * [paradise-test](#paradise-test)
30 | * [变更日志](#变更日志)
31 |
32 |
33 | # Paradise
34 |
35 | 在平时写一些小项目时,很多工具类都是重复的。一直以来都是复制修改,后来有一天又找不到了。
36 |
37 | 很繁琐,索性就将平时会用到的大多数东西放在这一个项目下面。
38 |
39 | [](http://mvnrepository.com/artifact/com.github.houbb/paradise)
40 | [](https://www.travis-ci.org/houbb/paradise?branch=release_1.1.2)
41 | [](https://coveralls.io/github/houbb/paradise?branch=release_1.1.2)
42 |
43 | ## paradise-common
44 |
45 | 提供通用工具。主要是自己项目使用。不依赖三方 jar。
46 |
47 | ## paradise-enhance
48 |
49 | 功能增强,依赖三方 jar。
50 |
51 | ## paradise-core
52 |
53 | 对于 `compile-annotation`(运行时注解) 进行整合。
54 |
55 | - log-analysis-core 整合过来
56 |
57 | @Log
58 |
59 | - cat-limiter 整合过来
60 |
61 | @LimitCount
62 |
63 | @LimitFrequency
64 |
65 | - @valid 的重新设计
66 |
67 | ## paradise-test
68 |
69 | 仅用于本项目自检测试。
70 |
71 |
72 | # 变更日志
73 |
74 | > [ChangeLog](doc/ChangeLog.md)
75 |
--------------------------------------------------------------------------------