`标签来完成这种复杂的表格了,譬如:
300 |
301 | ```html
302 |
303 |
304 | 会员登记表 |
305 | 姓名 |
306 | 个人信息 |
307 |
308 |
309 | 张三 | 男 | 25 | 未婚 |
310 |
311 |
312 | 李四 | 女 | 35 | 已婚 |
313 |
314 |
315 | 王五 | 男 | 45 | 离异 |
316 |
317 |
318 | ```
319 |
320 | 如你所见,我们在这里利用``标签的`colspan`和`rowspan`属性实现了表格中单元格的跨行和跨列,其渲染效果如下:
321 |
322 | 
323 |
324 | 当然,这也就意味着,我们在设计网页时用于绘制表格的那些技巧也都可以运用在这里,但请注意,使用Markdown写作的目的之一,就是希望将表现语义的元素与表现样式的元素分而治之。所以,我们在Markdown中使用`HTML`标签时也应该坚持这一原则,尽量只专注于内容的表达,而对于内容的呈现样式则尽量交由后续工作来处理(譬如上图中的“会员登记表”这五个字,似乎应该设定为在单元格中纵向显示)。
325 |
326 | 在掌握了这两种绘制表格的方式之后,我们就可以回到论文中去整理那些表格了,譬如:
327 |
328 | 
329 |
330 | ### 3.3.2 引用外部图形
331 |
332 | 在写作计算机专业论文的过程中,我们通常会需要用到各种各样的图形,以弥补文字在论述能力上的不足。按照图形的来源,我们大致上可以将写作过程中会用到的图形两大类:首先是**引用图形**,这类图形来自论文外部,包括实物照片、屏幕截图以及第三方制作的图表等,这也是我们最常用的一种在文章中插入图形的方式。在Markdown中,引用外部图形的语义元素对应的是`HTML`的` `语法,它的语法和网页超链接非常类似,即:
333 |
334 | ```Markdown
335 | 
336 | ```
337 |
338 | 在这里。`引用图形的URL`既可以是一个HTTP协议的网络URL,也可以是一个绝对路径或相对路径形式的本地URL。譬如:
339 |
340 | ```Markdown
341 | 这里有两张引用图形,一张来自网络:
342 |
343 | 
344 |
345 | 另一张来自本地计算机:
346 |
347 | 
348 | ```
349 |
350 | 其渲染效果如下:
351 |
352 | 
353 |
354 | 当然,如果我们觉得URL部分的字符串过长,影响文档的整洁美观,也可以采用另一种分离式的引用语法。即在图形引用之处为该URL设置一个别名,然后将该别名所代表的URL写在文档最后的注释区即可。譬如,对于上面那张来自网络的图形,我们还可以这样编码:
355 |
356 | ```Markdown
357 |
358 | 这里有两张引用图形,一张来自网络:
359 |
360 | ![来自网络的图形][img1]
361 |
362 | 另一张来自本地计算机:
363 |
364 | 
365 |
366 |
367 |
368 |
369 | [img1]:http://www.newasp.net/attachment/soft/2015/0713/085610_78002493.png
370 | ```
371 |
372 | 我们可以看到,上述编码的渲染效果与之前是完全一致的:
373 |
374 | 
375 |
376 | 接下来,我们再来看看如何在Markdown中用特定代码自动生成图形。
377 |
378 | ### 3.3.3 自动生成图形
379 |
380 | 虽然在大多数情况下,我们都更倾向于在文章中直接引用外部图形,但在一些特定情况下,我们也会需要用到一些少量的**生成图形**。这里所谓的**生成图形**,指的是我们在文章中直接使用某种特定代码自动生成的图形,这方面最常见的例子就是各种UML图,譬如流程图、序列图、甘特图等。在Markdown的诸多扩展中,`PlantUML`和`mermaid`无疑是目前使用最多的,用于自动生成图形的两款扩展库。在这里,我们打算以`mermaid`为例来介绍一下如何在Markdown文档中自动生成图形。如果有读者希望使用其它类似扩展库(譬如`PlantUML`[^1]或`flowchart.js`[^2]等),也不必担心,这些扩展库在使用方法上都大同小异,只要学会了其中一个,其它都只需要举一反三即可。
381 |
382 | `mermaid`是一个用于自动生成流程图、序列图、甘特图等UML图形的`JavaScript`程序库。正是由于这是一个JS库,所以它实际生成的并不是真正的“图形”,而是一段`HTML`代码,这让它可以更好地融入Markdown文档中。当然,我们在这里介绍的只是`mermaid`的基本用法,让读者对如何在Markdown文档中自动生成图形有一个总体上的认知。如果想更深入更全面地学会这个库,还请读者自行查阅`mermaid`库的官方文档[^3]。
383 |
384 | #### 3.3.3.1 生成流程图
385 |
386 | 众所周知,**流程图**实际上是对工作流的一种图形化表示,主要用于对程序的控制流和数据流进行建模,是最常用的UML行为图之一。所以,既然是要对工作流进行建模,那么定义流程图的第一步就是要先确定流程的走向。在`mermaid`中,描述流程图走向的语法如下:
387 |
388 | ```mermaid
389 | graph [流程图的走向]
390 | [其他描述语句...]
391 | ```
392 |
393 | 首先,要想在Markdown文档中使用`mermaid`库生成图形,我们需要将相关的代码区块标识为“`mermaid`”,这样文档的阅读器或转换器才能识别出这是一段`mermaid`代码,并调用相关引擎里来生成图形。然后,对于“`[流程图的走向]`”,我们可以有以下四种选择:
394 |
395 | | 走向描述 | 具体说明 |
396 | |---------|----------|
397 | | LR | 从左到右 |
398 | | RL | 从右到左 |
399 | | TB | 从上到下 |
400 | | BT | 从下到上 |
401 |
402 | 下面,我们继续来关注“`[其他描述语句...]`”的部分。在这一部分的工作中,首先要做的是定义流程图中的“节点”,这些“节点”代表了工作流中的开始、结束、决策、动作等要素。在`mermaid`中,每个“节点”都需要设置一个id,以及节点的形状与其中的文字,譬如:
403 |
404 | ```mermaid
405 | graph LR
406 | id1((A)) --> id2((B))
407 | id2 --> id3((C))
408 | id3 --> id1
409 | ```
410 |
411 | 其渲染效果如下:
412 |
413 | ```mermaid
414 | graph LR
415 | id1((A)) --> id2((B))
416 | id2 --> id3((C))
417 | id3 --> id1
418 | ```
419 |
420 | 在这里,`id1`、`id2`、`id3`分别是流程图中三个“节点”的id,而关于这些“节点”的形状,我们可以有下面几种选择:
421 |
422 | | 节点类型 | 相关说明 |
423 | |--------------|-------------|
424 | | `id[文字]` | 矩形节点 |
425 | | `id(文字)` | 圆角矩形节点 |
426 | | `id((文字))` | 圆形节点 |
427 | | `id>文字]` | 右向旗帜状节点 |
428 | | `id{文字}` | 菱形节点 |
429 |
430 | 请注意:如果"节点"中的文字中包含标点符号,需要用双引号把整段文字括起来。如果希望在文字中使用换行,请使用“` `”来替代换行。
431 |
432 | 在定义完"节点"之后,接下来就需要定义这些“节点”之间的“连线”了,在这部分,我们同样可以有以下几种选择:
433 |
434 | | 连线类型 | 相关说明 |
435 | |------------|-------------|
436 | | `>` | 添加尾部箭头 |
437 | | `-` | 不添加尾部箭头 |
438 | | `--` | 单线 |
439 | | `--text--` | 单线上加文字 |
440 | | `==` | 粗线 |
441 | | `==text==` | 粗线加文字 |
442 | | `-.-` | 虚线 |
443 | | `-.text.-` | 虚线加文字 |
444 |
445 | 除此之外,我们还可以在流程图中设置一个子图,子图的语法如下:
446 |
447 | ```mermaid
448 | graph [流程图的走向]
449 | [父图描述语句...]
450 | subgraph [子图名称]
451 | [子图描述语句...]
452 | end
453 | ```
454 |
455 | 现在,让我们综合一下刚才学到的语法,试着根据论文中要构建的系统来画一张流程图吧,例如在编辑器中输入如下代码:
456 |
457 | ```mermaid
458 | graph TD
459 | id1((用户)) --访问--> id2((导航栏))
460 | subgraph 书籍销售系统
461 | id2 --分类或搜索--> id3{查看图书信息}
462 | id2 --如果没有登录--> id4{用户登录}
463 | id2 --如果已经登录--> id5{查看交易记录}
464 | id2 --如果已经登录--> id6{查看购物车}
465 | id3 --加入采购清单--> id6
466 | id4 --登录成功--> id3
467 | id4 --登录成功--> id6
468 | id5 --支付未完成的交易-->id7((支付平台))
469 | id6 --立即购买--> id7
470 | id6 --延后付款--> id5
471 | end
472 | ```
473 |
474 | 只要我们安装了与`mermaid`相关的预览插件(譬如VSCode编辑器的mermaid Preview插件),应该就会看到如下效果:
475 |
476 | ```mermaid
477 | graph TD
478 | id1((用户)) --访问--> id2((导航栏))
479 | subgraph 书籍销售系统
480 | id2 --分类或搜索--> id3{查看图书信息}
481 | id2 --如果没有登录--> id4{用户登录}
482 | id2 --如果已经登录--> id5{查看交易记录}
483 | id2 --如果已经登录--> id6{查看购物车}
484 | id3 --加入采购清单--> id6
485 | id4 --登录成功--> id3
486 | id4 --登录成功--> id6
487 | id5 --支付未完成的交易-->id7((支付平台))
488 | id6 --立即购买--> id7
489 | id6 --延后付款--> id5
490 | end
491 | ```
492 |
493 | #### 3.3.3.2 生成序列图
494 |
495 | **序列图**也属于UML行为图中的一种,它的主要作用是描述既定活动序列上的交互行为,通常用来表示相关某一活动中的动作顺序,它的每一条消息都对应了一个动作或者触发状态转换的事件。在`mermaid`中,定义序列图的语法如下:
496 |
497 | ```mermaid
498 | sequenceDiagram
499 | [参与者1][消息线][参与者2]:[消息文本]
500 | ...
501 | ```
502 |
503 | 例如,假设我们想描述一个对话序列,就可以这样:
504 |
505 | ```mermaid
506 | sequenceDiagram
507 | A ->> B: 你最喜欢的小说是什么?
508 | B ->> A: 《福尔摩斯探案集》!
509 | ```
510 |
511 | 其渲染效果如下:
512 |
513 | ```mermaid
514 | sequenceDiagram
515 | A ->> B: 你最喜欢的小说是什么?
516 | B ->> A: 《福尔摩斯探案集》!
517 | ```
518 |
519 | 在这里,A和B都是该对话序列的“`[参与者]`”。当然,这是一个最简单的序列图,如果某活动序列中有多个“`[参与者]`,我们也可以单独用`participant`关键字来标明它们,譬如:
520 |
521 | ```mermaid
522 | sequenceDiagram
523 | participant A
524 | participant B
525 | participant C
526 | ...
527 | · ```
528 |
529 | 而且,我们还可以采用`participant [别名] as [参与者]`的形式,为相关参与者设置别名,譬如:
530 |
531 | ```mermaid
532 | sequenceDiagram
533 | participant A as Alice
534 | participant B as Bill
535 | participant C as Chioe
536 | ...
537 | ```
538 |
539 | 同样地,在定义完“`[参与者]`”之后,我们还需要定义它们之间的“`[消息线]`”。对于“`[消息线]`”,`mermaid`为我们提供了以下几种选择:
540 |
541 | | 消息线类型 | 具体说明 |
542 | |----------|------------------------|
543 | | `->` | 无箭头的实线 |
544 | | `-->` | 无箭头的虚线 |
545 | | `->>` | 有箭头的实线 |
546 | | `-->>` | 有箭头的虚线 |
547 | | `-x` | 末端为叉的实线(表示异步) |
548 | | `--x` | 末端为叉的虚线(表示异步) |
549 |
550 | 最后一部分是每一个序列的“`[消息文本]`”,这代表的是序列参与者之间所传递的消息内容,譬如在上面的例子中,A抛给B的消息是“`你最喜欢的小说是什么?`”,而B回复给A的消息则是“`《福尔摩斯探案集》!`”。
551 |
552 | 除了以上这些序列图的基本元素之外,我们还可以在序列图中加入一些更详细的信息。譬如标记相关消息的处理状态:
553 |
554 | - 在消息线末尾增加`+` ,则消息接收者进入当前消息的“处理中”状态。
555 | - 在消息线末尾增加`-` ,则消息接收者离开当前消息的“处理中”状态。
556 |
557 | 或者直接用以下语法来标记明某个参与者进入“处理中”状态:
558 |
559 | ```mermaid
560 | activate [参与者]
561 | ```
562 |
563 | 再譬如,我们可以在某些指定位置上添加一些标注,其语法如下:
564 |
565 | ```mermaid
566 | Note [标注位置] [参与者]: [标注文字]
567 | ```
568 |
569 | 在这里,对于”`[标注位置]`“的描述,我们可以有以下几种选择:
570 |
571 | | 位置描述 | 具体说明 |
572 | |------------|-----------------------|
573 | | `right of` | 在参与者的右侧 |
574 | | `left of` | 在参与者的左侧 |
575 | | `over` | 在当中,可以横跨多个参与者 |
576 |
577 | 最后,我们还可以在序列图中标记一些控制消息传递的控制结构,其语法如下:
578 |
579 | - **循环结构**:
580 |
581 | ```mermaid
582 | loop [循环条件]
583 | [循环体描述语句]
584 | end
585 | ```
586 |
587 | - **条件判断**:
588 |
589 | ```mermaid
590 | alt [条件1 描述]
591 | [分支1 描述语句]
592 | else [条件2 描述] # else 分支可选
593 | [分支2 描述语句]
594 | else ...
595 | ...
596 | end
597 | ```
598 |
599 | 最后,和之前一样,让我们综合一下上面的语法,试着根据写论文的情境来画一张序列图吧。例如在编辑器中输入如下代码:
600 |
601 | ```mermaid
602 | sequenceDiagram
603 | participant 张三
604 | participant 李四
605 | participant 王五
606 | 张三 -> 王五: 老王,你论文写好了吗?
607 | loop 检查论文
608 | 王五 -> 王五: 确认完成度
609 | end
610 | Note right of 王五: 再三确认 再回答……
611 | 王五 --> 张三: 写好了,但还需修改。
612 | 王五 -> 李四: 你怎么样?
613 | 李四 --> 王五: 我已经发给老师了!
614 | ```
615 |
616 | 同样地,只要我们安装了与`mermaid`相关的预览插件,应该就会看到如下效果:
617 |
618 | ```mermaid
619 | sequenceDiagram
620 | participant 张三
621 | participant 李四
622 | participant 王五
623 | 张三 -> 王五: 老王,你论文写好了吗?
624 | loop 检查论文
625 | 王五 -> 王五: 确认完成度
626 | end
627 | Note right of 王五: 再三确认 再回答……
628 | 王五 --> 张三: 写好了,但还需修改。
629 | 王五 -> 李四: 你怎么样?
630 | 李四 --> 王五: 我已经发给老师了!
631 | ```
632 |
633 | ## 本章小结
634 |
635 | 在这一章中,我们首先介绍了如何用VSCode编辑器创建一个Markdown文档项目。然后,我们从组织论文的文本切入,依次介绍了如何在Markdown文档中进行文本的分段和换行、强调重点、引用外部文字和图片、展现程序代码以及绘制表格。最后,我们还以用`mermaid`库生成流程图和序列图为例,介绍了如何在Markdown文档中自动生成图形。
636 |
637 | 到目前为止,我们已经介绍了用Markdown撰写一篇计算机专业的大学论文所需的大部分基本技能,唯一尚未提及的是关于数学问题的讨论,这正是我们在下一章中要讨论的问题。
638 |
639 |
640 |
641 | [^1]:注释:官方网站:http://plantuml.com/zh/
642 | [^2]:注释:官方网站:http://flowchart.js.org/
643 | [^3]:注释:官方网站:https://mermaidjs.github.io/
644 |
--------------------------------------------------------------------------------
/src/04_第四章.md:
--------------------------------------------------------------------------------
1 | # 第4章 谈谈数学问题
2 |
3 | ## 本章提要
4 |
5 | 在之前的两章中,我们以笔者本科毕业论文的撰写过程为导引,逐一为大家介绍了Markdown的基本语法,以及这种轻量型标记语言在写作阶段的大部分应用。到目前为止,关于写作阶段的内容,我们就只剩下“如何用Markdown来描述数学问题”这一议题没有讨论了。之所以一直避而不谈这个议题,一方面是因为笔者的这篇论文主要论证的是一个网上书籍销售系统的构建过程,本身并没有涉及到数学问题。另一方面,更重要的是因为在Markdown文档中描述数学问题要涉及到$\LaTeX$标记的运用,相对比较复杂,所以我们打算单独用一章的篇幅来讨论这个议题。
6 |
7 | 在这一章中,我们首先会介绍如何在Markdown文档中插入$\LaTeX$标记,以呈现数学公式。然后,我们会具体介绍如何用$\LaTeX$标记来描述基本四则运算、二项式方程、矩阵运算以及集合运算等数学问题。相信在学习完本章的内容之后,大家应该都能随心所欲地在Markdown文档中讨论数学问题了。
8 |
9 | ## 4.1 使用$\LaTeX$标记
10 |
11 | 在Markdown中,数学问题的描述是通过引入$\LaTeX$标记来完成的。由于$\LaTeX$本身就是一门独立的标记语言,所以在介绍如何引入其相关标记之前,我们最好先对这门语言做一个简单的介绍。
12 |
13 | ### 4.1.1 $\LaTeX$是什么?
14 |
15 | 事情得从$\TeX$说起,众所周知,$\TeX$是美国著名的计算机教授高德纳(Donald Ervin Knuth)[^1]为撰写其伟大著作《计算机程序设计艺术》专门开发的一套排版系统。由于《计算机程序设计艺术》是一部讨论计算机算法的鸿篇巨作,其中涉及了大量的数学问题,所以为其开发的排版系统自然就在编辑复杂的数学公式方面具备了与生俱来的优势,这种先天优势使得它在数学、物理学和计算机科学等与数学表述密切相关的学术领域中非常流行,甚至很多人学习$\TeX$就是为了使用它在数学领域中的强大表述能力。
16 |
17 | 但$\TeX$的功能过于强大,它会要求我们在排版过程中精确描述到每一个细节,有时甚至是一个字母或标点也要照顾到。这对于大多数人来说,可能就学习成本太高,并且用起来太过繁琐和费时了。于是在上个世纪80年代,美国计算机科学家莱斯利·兰伯特(Leslie Lamport)[^2]在$\TeX$的基础上开发出了$\LaTeX$这个新的排版系统(目前的版本为$\LaTeX2e$)。从本质上来说,该排版系统其实就是一组封装了$\TeX$处理细节的宏,它可以让那些不了解排版和程序设计相关知识的人们也能使用$\TeX$所提供的强大功能,并在几天甚至几个小时之内就能排版出具有专业质感的印刷品,而不必深陷于琐碎的排版细节中。
18 |
19 | 在中文支持方面,$\LaTeX$目前主要使用的`XeTeX`排版引擎,该引擎支持UTF-8编码和现代字体,可以直接使用本地计算机中安装的字体,这大大降低了$\LaTeX$的使用难度。
20 |
21 | ### 4.1.2 插入$\LaTeX$标记
22 |
23 | 正如上面所说的,$\LaTeX$本质上是一组封装了$\TeX$处理细节的宏。所以我们接下来所使用的每一个标记实际上都是一个宏。$\LaTeX$的这些标记主要有两种形式,第一种形式是数学公式,而数学公式的编辑原本就是本章的主要议题,我们会在下一节中做详细介绍。在这里,我们要先来简单了解一下$\LaTeX$标记的命令形式,因为这种形式也会出现在复杂的公式中。这种形态的$\LaTeX$标记通常会以一个反斜杠开头,后面紧接着该命令的名称,这个名称既可能是个单一符号,也可能是一个字符串。命令名称之后还可以有一些指定参数,我们通常会用花括号将它们括起来(如果该参数只有一个字符,花括号可以省略)。除此之外,如果有可选参数,则用方括号括起来,具体如下:
24 |
25 | - 无参数形式:`\command`。
26 | - 有参数形式:`\command{参数1}{参数2}……{参数N}`。
27 | - 带可选参数形式:`\command[可选参数]{参数1}{参数2}……{参数N}`。
28 |
29 | 例如,我们现在这里所显示的“$\LaTeX$”字样,使用的就是一个无参数形式的$\LaTeX$标记`\LaTeX`。再例如,我们之前所使用开方标记`\sqrt`,就需要有一个指定参数来表示被开方数。另外,我们还可以用该标记的可选参数来指定开方的次数。关于`\sqrt`标记的具体使用,我们在下一节中会详细介绍。
30 |
31 | 在Markdown中,引入$\LaTeX$标记的工作是靠`Mathjax`库[^3]来完成的。和我们之前使用`Mermaid`库一样,`MathJax`也是一个跨浏览器的`JavaScript`程序库,它使用`MathML`、`LaTeX`和`ASCIIMathML`标记在Web浏览器中显示数学符号。当然,在使用这个库之前,必须要先确认我们所使用的Markdown编辑器是支持`Mathjax`的,譬如在VSCode编辑器中,我们需要安装Markdown+Math插件。
32 |
33 | 在设置好编辑环境之后,我们就可以在Markdown文档中插入$\LaTeX$标记了。具体来说,$\LaTeX$标记的引用方式主要有以下两种:
34 |
35 | - **行内引用**:采用行内引用方式的$\LaTeX$标记通常与正常文本处于同一逻辑行中(软件界面导致的自动换行不算),具体语法就是*在待引用标记的前后各加一个美元符号*。例如,如果我们想显示“我正在使用$\LaTeX$来排版论文。”这句话,只需进行如下编码即可:
36 |
37 | ```Markdown
38 | 我正在使用$\LaTeX$来排版论文。
39 | ```
40 |
41 | - **单独引用**:采用单独引用方式的$\LaTeX$标记通常会独立于正常文本,自成一行,具体语法就是*在待引用标记的前后各加两个美元符号*。例如,如果我们想讨论勾股定理,就可以使用如下编码来描述该定理:
42 |
43 | ```Markdown
44 | 在平面上的一个直角三角形中,如果设直角三角形的两条直角边长度分别是a和b,斜边长度是c,那么按照勾股定理,这三边的关系如下:
45 |
46 | $$ a^{2} + b^{2} = c^{2} $$
47 |
48 | 这也就意味着:
49 |
50 | $$ a = \sqrt{c^{2} - b^{2}} $$
51 | $$ b = \sqrt{c^{2} - a^{2}} $$
52 | $$ c = \sqrt{a^{2} + b^{2}} $$
53 | ```
54 |
55 | 其渲染效果如下
56 |
57 | > 在平面上的一个直角三角形中,如果设直角三角形的两条直角边长度分别是a和b,斜边长度是c,那么按照勾股定理,这三边的关系如下:
58 | >
59 | > $$ a^{2} + b^{2} = c^{2} $$
60 | >
61 | > 这也就意味着:
62 | >
63 | > $$ a = \sqrt{c^{2} - b^{2}} $$
64 | > $$ b = \sqrt{c^{2} - a^{2}} $$
65 | > $$ c = \sqrt{a^{2} + b^{2}} $$
66 |
67 | 请暂时不用担心看不懂上面所使用的$\LaTeX$标记,因为我们会在下一节中详细介绍这些标记及其使用方法。在这里,大家只需要对$\LaTeX$标记的引用方式有清楚的认知就可以了。
68 |
69 | ## 4.2 编辑数学公式
70 |
71 | 数学公式的编辑一直以来都是我们在撰写科学类文章过程中所面临的最大麻烦之一,相信各位之前应该都尝试过各种在电子文档中输入数学公式的方法,但这些方法多数都不尽如人意,这恐怕也是驱使很多人最终下定决心来学习$\LaTeX$的主要原因。毕竟,对数学公式进行编辑和排版本身就是$\TeX$最重要的设计初衷之一,目前似乎也找不到比它更强大的数学公式编辑方法了。所以在接下来的内容中,我们就来详细、深入地介绍一下如何用$\LaTeX$编辑数学公式。
72 |
73 | ### 4.2.1 初识公式
74 |
75 | 众所周知,数学公式与普通文本最大的不同就在于,数学公式中的每一个字符都有特定的含义,这些字符并不像普通文本那样只是单纯地横向或纵向排列,它们有一套属于自己的特殊结构和规则。例如,在上面勾股定理的推导公式中:
76 |
77 | $$ c = \sqrt{a^{2} + b^{2}} $$
78 |
79 | 我们可以看到,$a$和$b$都由各自的平方号,外面还套着一个开根号,这些数学符号的排列既复杂又井然有序,在电子文档中实现这样的排列结构就是我们使用$\LaTeX$编辑数学公式要完成的主要工作。
80 |
81 | 在$\LaTeX$中,数学公式按照$\LaTeX$表示引用方式的不同,也可以分为采用行内引用的**行内公式**和采用单独引用的**行间公式**两大类。譬如$f(x,y)= x^2 + y^2$,这就是一个行内公式,它们通常与普通文本同处于一个逻辑行内。而行间公式则就是我们在上面关于描述沟勾股定理的示例所看到的那种形式,它们通常独立于普通文本,自成一行。
82 |
83 | 在了解了数学公式的独特性和它们在文档中的引用形式之后,接下来就可以正式开始学习数学公式的编辑了。下面,让我们先从最基本的加减法开始。在Markdown中编写加减运算的公式很简单,就是在相应的数学表达式加上$\LaTeX$标记,譬如,如果我们想编写$x=a+b-c$这样的公式,就只需要输入`$x=a+b-c$`即可(当然也可以使用行间公式的形式)。在这里,大家心里可能会有一个疑问:加减运算中使用的符号都是可以直接从键盘输入的,描述这类运算时似乎没有必要使用$\LaTeX$标记吧?要想回答这个疑问,我们不妨先来看看使用$\LaTeX$标记前后的区别:
84 |
85 | 
86 |
87 | 如你所见,相同的表达式在使用了$\LaTeX$标记之后,表达式中的每个字符都被设置了特定的字体。譬如,字母采用了倾斜的意大利字体,而数字和加号则采用的是直立的等宽字体,并且每个字符之间也都设置了相应的间距。正是这些排版样式将一个干巴巴的表达式变成了具有学术质感的数学公式。所以,即使没有用到任何特殊符号,我们也会建议读者尽量使用$\LaTeX$标记来描述数学问题。
88 |
89 | ### 4.2.2 公式结构
90 |
91 | 正如我们之前所说,编辑数学公式并不是在简单地堆砌一堆数学符号,它们都是一些特定结构的组合。我们可以仔细回想一下自己迄今为止所见过的各种公式,看看是不是能从中提炼出几种特定的公式结构?这些结构中有哪些规则?下面我们就来回答一下这两个问题,用$\LaTeX$标记来描述一下这些公式结构。
92 |
93 | #### 4.2.3.1 上标与下标
94 |
95 | 在众多数学公式中,上标和下标无疑是两种最常见的公式结构了。其中,上标通常位于其目标符号的右上方,而下标则通常位于其目标符号的右下方,但在某些情况下,它们也会出现在目标符号的正上方和正下方,例如$10^2$、$a_i$、$a^2_i$、$\sum\limits_{i=0}^n$等。
96 |
97 | 在$\LaTeX$中,上标用特殊字符“^”表示,下标用特殊字符“`_`”表示,上标和下标可以同时作用于同一个目标符号,并且它们的顺序是可以互换的,我们可以先写上标再写下标,也可以反过来写,两者互不影响。另外,如果上标或下标的内容的多于一个字符,就用括号将其括起来。下面来具体演示一下:
98 |
99 | | 公式编码 | 渲染效果 |
100 | |---------------------|-------------------|
101 | | `$10^2$` | $10^2$ |
102 | | `$2^{1024}$` | $2^{1024}$ |
103 | | `$a_i$` | $a_i$ |
104 | | `$a_{i+1}$` | $a_{i+1}$ |
105 | | `$a_i^2$` | $a_i^2$ |
106 | | `$a^2_i$` | $a^2_i$ |
107 | | `$A_{i,j}=2^{i+j}$` | $A_{i,j}=2^{i+j}$ |
108 |
109 | 除此之外,上标与下标之间还是可以相互嵌套的,譬如:
110 |
111 | | 公式编码 | 渲染效果 |
112 | |---------------------|-------------------|
113 | | `$2^{n_i}$` | $2^{n_i}$ |
114 | | `$2_{n^i}$` | $2_{n^i}$ |
115 | | `$2^{n^i}$` | $2^{n^i}$ |
116 | | `$2_{n_i}$` | $2_{n_i}$ |
117 | | `$2^{2^{2^{2}}}$` | $2^{2^{2^{2}}}$ |
118 |
119 | 在求和、积分等这类算子符号上,$\LaTeX$基于排版因素的考虑,为避免文字过于拥挤或难看的行间距,对于行内公式和行间公式的上下标位置有不同的处理,譬如以求和式为例,其行内公式的上下标位于求和符号的右上角和右下角,而行间公式则位于求和符号的正上方和正下方。当然,我们也可以使用特定的$\LaTeX$标记来指定上下标的位置。例如,如果想让求和式的行内公式采用与行间公式相同的上下标位置,可以对它使用`\limits`标记。下面,我们来具体演示一下求和式的上下标:
120 |
121 | 
122 |
123 | 不止如此,我们还可以引用`amsmath`宏组[^4]中的$\LaTeX$标记,对上下标的位置进行更精确的指定。例如使用`\sideset`标记,可以在一个符号的四个角上各指定一个上下标。除此之外,我们还可以通过`\overset`或`\underset`标记来指定一般符号的上下标位于其正上方或正下方。下面,我们就来演示一下这些标记的使用:
124 |
125 | | 公式编码 | 渲染效果 |
126 | |-------------------------------------|-----------------------------------|
127 | | `$\sideset{^a_b}{} A$` | $\sideset{^a_b}{}{A}$ |
128 | | `$\sideset{}{^c_d} A$` | $\sideset{}{^c_d}{A}$ |
129 | | `$\sideset{^a_b}{^c_d} A$` | $\sideset{^a_b}{^c_d}{A}$ |
130 | | `$\overset{*}{A}$` | $\overset{*}{A}$ |
131 | | `$\underset{*}{A}$` | $\underset{*}{A}$ |
132 | | `$\overset{*}{\underset{*}{A}}$` | $\overset{*}{\underset{*}{A}}$ |
133 |
134 | 对于`amsmath`宏组中其他与上下标相关的$\LaTeX$标记,读者可以自行参考相关的$\LaTeX$文档,这里就不再一一累述了。
135 |
136 | #### 4.2.3.2 线条与括号
137 |
138 | 我们在进行数学公式的推演和分析时,经常会需要在公式的上下方画上一些线或者花括号,以便标注一些信息,这也形成了一种独特的**标注结构**。在这一节中,我们就来介绍一下这种结构的公式编辑。先来看最简单的线条标注,在$\LaTeX$中,线条标注是通过`\overline`和`\underline`这两个标记来完成的。请注意,这两个标记不止可以作用在一般结构的数学公式上,它们可以与任意结构的公式进行嵌套组合。下面,我们来演示一下它们的用法:
139 |
140 | | 公式编码 | 渲染效果 |
141 | |-----------------------------------------------|---------------------------------------------|
142 | | `$\overline{ab}=\overline{a}*\overline{b}$` | $\overline{ab}=\overline{a}*\overline{b}$ |
143 | | `$\underline{c}=\underline{a^2+b^3}$` | $\underline{c}=\underline{a^2+b^3}$ |
144 | | `$\underline{\overline{a^2}+\overline{b}^3}$` | $\underline{\overline{a^2}+\overline{b}^3}$ |
145 | | `$a^{\overline{2}}+b^{\underline{^3}}$` | $a^{\overline{2}}+b^{\underline{^3}}$ |
146 |
147 | 除此之外。我们还可以使用`amsmath`宏组中提供的六种带箭头的线条:
148 |
149 | | 公式编码 | 渲染效果 |
150 | |-------------------------------|-----------------------------------|
151 | | `$\overrightarrow{a+b}$` | $\overrightarrow{a+b}$ |
152 | | `$\overleftarrow{a+b}$` | $\overleftarrow{a+b}$ |
153 | | `$\overleftrightarrow{a+b}$` | $\overleftrightarrow{a+b}$ |
154 | | `$\underrightarrow{a+b}$` | $\underrightarrow{a+b}$ |
155 | | `$\underleftarrow{a+b}$` | $\underleftarrow{a+b}$ |
156 | | `$\underleftrightarrow{a+b}$` | $\underleftrightarrow{a+b}$ |
157 |
158 | 学习完线条标注的方法之后,接下来我们来看看如何用花括号来进行标注。在$\LaTeX$中,公式上下方的花括号标注是用`\overbrace`和`\underbrace`这两个标记来完成的,它们与之前线条标注之间最大的区别,就是花括号可以通过上标和下标来对公式进行文字标注,这在我们描述数学公式的分析过程中是非常有用的。下面我们就来演示一下这两个标记的用法:
159 |
160 | | 公式编码 | 渲染效果 |
161 | |--------------------------------------------------|------------------------------------------------|
162 | | `$a+c-\overbrace{b \times d}$` | $a+c-\overbrace{b \times d}$ |
163 | | `$a+c-\underbrace{b\times d}$` | $a+c-\underbrace{b \times d}$ |
164 | | `$a+c-\overbrace{b \times d}^{\text{乘法优先}}$` | $a+c-\overbrace{b \times d }^{\text{乘法优先}}$ |
165 | | `$a+c-\underbrace{b \times d}_{\text{乘法优先}}$` | $a+c-\underbrace{b \times d}_{\text{乘法优先}}$ |
166 |
167 | #### 4.2.3.3 分式与根式
168 |
169 | 由于**分式**与**根式**都属于数学公式中极为常见的结构,并且它们在结构上也都相对简单,所以,我们打算将它们放在同一节中来介绍。先从**分式**开始,在$\LaTeX$中,分式是通过`\frac`标记来实现的,其第一个参数为分子,第二个参数为分母。下面,我们来演示一下分式标记的具体使用:
170 |
171 | | 公式编码 | 渲染效果 |
172 | |-------------------------------|-----------------------------------|
173 | | `$\frac{1}{2}$` | $\frac{1}{2}$ |
174 | | `$\frac{1}{a}$` | $\frac{1}{a}$ |
175 | | `$\frac{1}{a+b}$` | $\frac{1}{a+b}$ |
176 | | `$\frac{a+b}{2}$` | $\frac{a+b}{2}$ |
177 |
178 | 请注意,我们在表格中使用的都是分式的行内公式形态,如果拿它们对比一下分式的行间公式形态,就会发现其行内公式形态的分子和分母都使用了较小的字号,以配合普通文本的行高和行间距,以影响排版的整体质感,譬如:
179 |
180 | 
181 |
182 | 当然,有时在行间公式中,我们也会想要让公式某一部分的字体小一点,采用行内公式形态,某一部分的字体大一点,采用行间公式形态。这时候,我们就可以使用`amsmath`宏组中提供的`\dfrac`(行间形态)和`\tfrac`(行内形态)来具体指定。譬如通过如下公式的比对,我们可以看到使用指定标记之后的效果:
183 |
184 | 
185 |
186 | 除此之外,我们还会看到一些类似的、分上下两层的公式结构,譬如二项式系数,它使用的是`\binom`标记,用法与分式标记完全一致,这里就不一一累述了。下面,我们来看看**根式**的结构,在$\LaTeX$中,根式是通过`\sqrt`标记来完成,该命令标记除了用于表示被开方数的指定参数外,还可以通过一个可选参数来表示开方的次数。我们来演示一下根式标记的具体使用:
187 |
188 | | 公式编码 | 渲染效果 |
189 | |-------------------------------|-----------------------------------|
190 | | `$\sqrt{4}$` | $\sqrt{4}$ |
191 | | `$\sqrt[3]{8}$` | $\sqrt[3]{8}$ |
192 | | `$\sqrt[n]{a+b}$` | $\sqrt[n]{a+b}$ |
193 | | `$\sqrt[n]{\frac{1}{a+b}}$` | $\sqrt[n]{\frac{1}{a+b}}$ |
194 |
195 | 同样地。我们也可以使用`amsmath`宏组中提供的标记,对根式的排版样式做一些指定。例如,在一般状况下,根式的高度是随着其内容变化的,但当我们需要将几个根式并列出现在同一个公式中时,就会希望这些根式的高度是一致的,这时候就会需要用到`\vphantom`标记。我们可以来比对一下该标记使用之后的效果:
196 |
197 | 
198 |
199 | 再例如,我们还可以通过`\uproot`和`\leftroot`这两个标记来调整开方次数所显示的位置,这两个命令标记的参数允许我们输入基于标准位置的偏移单位(正数代表上移或左移,负数代表下移或右移),以调整位置:
200 |
201 | 
202 |
203 | #### 4.2.3.4 矩阵公式
204 |
205 | 现在我们来介绍最后一种公式结构:**矩阵**。在$\LaTeX$中,矩阵不同于一般的公式结构,它是一个独立的排版单元。因此在编辑矩阵时,我们需要先用单元定义标记`\begin`和`\end`来定义一个样式为`matrix`的独立单元。例如,下面是两个$2*2$的矩阵在执行加法运算:
206 |
207 | ```Markdown
208 | $$
209 | \begin{matrix}
210 | a & b \\
211 | c & d \\
212 | \end{matrix}
213 | +
214 | \begin{matrix}
215 | a & b \\
216 | c & d \\
217 | \end{matrix}
218 | $$
219 | ```
220 |
221 | 正如你所见,在上述矩阵的定义过程中,不同的列之间用符号“`&`”分隔,不同的行之间则用“`\\`”分割,其渲染效果如下:
222 |
223 | > $$
224 | > \begin{matrix}
225 | > a & b \\
226 | > c & d \\
227 | > \end{matrix}
228 | > +
229 | > \begin{matrix}
230 | > a & b \\
231 | > c & d \\
232 | > \end{matrix}
233 | > $$
234 |
235 | 但是,我们发现这样的矩阵在样式上实在太过简陋,尤其在当我们像上面一样,将多个矩阵并列写在同一个公式中时,它们似乎应该要有个边框会更好。所以,如今我们更常用的是`amsmath`宏组中提供的其他五种矩阵样式,下面我们就来看看这些矩阵样式与原生样式的对比:
236 |
237 | |matrix|pmatrix|bmatrix|Bmatrix|vmatrix|Vmatrix|
238 | |:--:|:--:|:--:|:--:|:--:|:--:|
239 | | $\begin{matrix} a & b \\ c & d \\ \end{matrix}$ | $\begin{pmatrix} a & b \\ c & d \\ \end{pmatrix}$ | $\begin{bmatrix} a & b \\ c & d \\ \end{bmatrix}$ | $\begin{Bmatrix} a & b \\ c & d \\ \end{Bmatrix}$ | $\begin{vmatrix} a & b \\ c & d \\ \end{vmatrix}$ | $\begin{Vmatrix} a & b \\ c & d \\ \end{Vmatrix}$ |
240 |
241 | 这些标记的方法大同小异,只要将`\begin`和`\end`中的`matrix`参数改成相应的矩阵样式名称即可。比如,如果我们想为之前参与加法运算的矩阵加上一个中括号,就可以这样做:
242 |
243 | ```Markdown
244 | $$
245 | \begin{bmatrix}
246 | a & b \\
247 | c & d \\
248 | \end{bmatrix}
249 | +
250 | \begin{bmatrix}
251 | a & b \\
252 | c & d \\
253 | \end{bmatrix}
254 | $$
255 | ```
256 |
257 | 其渲染效果如下:
258 |
259 | > $$
260 | > \begin{bmatrix}
261 | > a & b \\
262 | > c & d \\
263 | > \end{bmatrix}
264 | > +
265 | > \begin{bmatrix}
266 | > a & b \\
267 | > c & d \\
268 | > \end{bmatrix}
269 | > $$
270 |
271 | 当然,如果某些矩阵过大,且无需将其中的元素全部输入,也可以在矩阵中使用`\cdots`、`\ddots`、`\vdots`这三个标记来输入一些省略号,以表示这些被省略的元素。例如:
272 |
273 | ```Markdown
274 | $$
275 | \begin{bmatrix}
276 | 1 & a_1 & a_1^2 & \cdots & a_1^n \\
277 | 1 & a_2 & a_2^2 & \cdots & a_2^n \\
278 | \vdots & \vdots & \vdots & \ddots & \vdots \\
279 | 1 & a_m & a_m^2 & \cdots & a_m^n \\
280 | \end{bmatrix}
281 | $$
282 | ```
283 |
284 | 在这里,`\cdots`代表的是横向省略号、`\ddots`则代表了斜向省略号、而`\vdots`则代表纵向省略号,其渲染效果如下:
285 |
286 | > $$
287 | > \begin{bmatrix}
288 | > 1 & a_1 & a_1^2 & \cdots & a_1^n \\
289 | > 1 & a_2 & a_2^2 & \cdots & a_2^n \\
290 | > \vdots & \vdots & \vdots & \ddots & \vdots \\
291 | > 1 & a_m & a_m^2 & \cdots & a_m^n \\
292 | > \end{bmatrix}
293 | > $$
294 |
295 | 在矩阵中0元素比较多的情况下,我们还可以使用嵌套矩阵的方法来编写一个分块矩阵,例如:
296 |
297 | ```Markdown
298 | $$
299 | \begin{bmatrix}
300 | \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} & \Large{0} \\
301 | \Large{0} & \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} \\
302 | \end{bmatrix}
303 | $$
304 | ```
305 |
306 | 如你所见,我们实际上是让内嵌矩阵成为了外层矩阵的元素,其渲染效果如下:
307 |
308 | > $$
309 | > \begin{bmatrix}
310 | > \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} & \Large{0} \\
311 | > \Large{0} & \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} \\
312 | > \end{bmatrix}
313 | > $$
314 |
315 | 以上这些矩阵采用的都是行间公式的形态,但我们有时候也会在普通文本中编写一些简单的行内矩阵,这就需要用很小的字体来显示矩阵,这时候就可以采用`amsmath`宏组中提供的`smallmatrix`行内矩阵样式。当然,由于这种矩阵样式并没有设置括号,所以我们要手工为其添加一对括号,例如:
316 |
317 | ```Markdown
318 | 我们也可以用$\left[ \begin{smallmatrix} a & -b \\ b & a \end{smallmatrix} \right]$这样的矩阵来表示一个复数。
319 | ```
320 |
321 | 其渲染效果如下:
322 |
323 | > 我们也可以用$\left[ \begin{smallmatrix} a & -b \\ b & a \end{smallmatrix} \right]$这样的矩阵来表示一个复数。
324 |
325 | ### 4.2.3 数学公式中的符号
326 |
327 | 在掌握了以上几种公式结构之后,我们就基本上能够构建起一个数学公式的主要骨干了。但是,数学公式具体要计算的内容则还是需要其使用的具体数学符号来决定。在$\LaTeX$中,我们可以将数学公式中的符号按照作用分成三大类,它们分别用于标记字母与字体、运算与关系、分隔与连接这三种数学语义。在这一节中,我们就来介绍一下这三大类数学符号中比较常用的部分符号。如果读者想要知道全部的数学符号,还需要自行去查阅相关的$\TeX$文档。
328 |
329 | #### 4.2.3.1 字母与字体
330 |
331 | 让我们先从字母开始,数学公式中使用的字母主要为拉丁字母和希腊字母。其中,拉丁字母就是英文所用的字母,这26个字母(包括其大小写形态)都可以直接从键盘输入,不需要特定的标记来表示。但希腊字母的情况就要复杂一些了,除了部分字母与拉丁字母一致,可以直接用键盘输入外,其他就必须要用特定的$\LaTeX$标记来表示了,其字母表如下:
332 |
333 | | 字母标记 | 显示效果 | 字母标记 | 显示效果 | 字符标记 | 显示效果 | 字符标记 | 显示效果 |
334 | |:---------:|:----------:|:---------:|:---------:|:----------:|:----------:|:----------:|:----------:|
335 | | `\alpha` | $\alpha$ | `A` | $A$ | `\beta` | $\beta$ | `B` | $B$ |
336 | | `\gamma` | $\gamma$ | `\Gamma` | $\Gamma$ | `\delta` | $\delta$ | `\Delta` | $\Delta$ |
337 | |`\epsilon` | $\epsilon$ | `E` | $E$ | `\zeta` | $\zeta$ | `Z` | $Z$ |
338 | | `\eta` | $\eta$ | `H` | $H$ | `\theta` | $\theta$ | `\Theta` | $\Theta$ |
339 | | `\iota` | $\iota$ | `I` | $I$ | `\kappa` | $\kappa$ | `K` | $K$ |
340 | | `\lambda` | $\lambda$ | `\Lambda` | $\Lambda$ | `\mu` | $\mu$ | `M` | $M$ |
341 | | `\nu` | $\nu$ | `N` | $N$ | `\xi` | $\xi$ | `\Xi` | $\Xi$ |
342 | | `o` | $o$ | `O` | $O$ | `\pi` | $\pi$ | `\Pi` | $\Pi$ |
343 | | `\rho` | $\rho$ | `P` | $P$ | `\sigma` | $\sigma$ | `\Sigma` | $\Sigma$ |
344 | | `\tau` | $\tau$ | `T` | $T$ | `\upsilon` | $\upsilon$ | `\Upsilon` | $\Upsilon$ |
345 | | `\phi` | $\phi$ | `\Phi` | $\Phi$ | `\chi` | $\chi$ | `X` | $X$ |
346 | | `\psi` | $\psi$ | `\Psi` | $\Psi$ | `\omega` | $\omega$ | `\Omega` | $\Omega$ |
347 |
348 | 这其中,部分希腊字母还有变量专用形态,它们的$\LaTeX$标记通常以`\var-`开头,具体如下:
349 |
350 | | 小写形态 | 大写形态 | 变量形态 | 显示效果 |
351 | |:----------:|:--------:|:-------------:|:-----------------------------------:|
352 | | `\epsilon` | `E` | `\varepsilon` | $\epsilon \mid E \mid \varepsilon$ |
353 | | `\theta` | `\Theta` | `\vartheta` | $\theta \mid \Theta \mid \vartheta$ |
354 | | `\rho` | `P` | `\varrho` | $\rho \mid P \mid \varrho$ |
355 | | `\sigma` | `\Sigma` | `\varsigma` | $\sigma \mid \Sigma \mid \varsigma$ |
356 | | `\phi` | `\Phi` | `\varphi` | $\phi \mid \Phi \mid \varphi$ |
357 |
358 | 下面,我们再来看看这些字母使用的字体。在通常情况下,数学公式中的变量采用的是斜体的意大利体,常数采用的是直体的罗马体。当然,在特定情况下,我们也可以用以下$\LaTeX$标记来指定相关字母的字体:
359 |
360 | | 字体标记 | 字体名称 | 显示效果 | 字体标记 | 字体名称 | 显示效果 |
361 | |:-------:|:--------:|:--------------:|:------:|:-------:|:--------------:|
362 | | `\rm` | 罗马体 | $\rm{Sample}$ | `\cal` | 花体 | $\cal{SAMPLE}$ |
363 | | `\it` | 意大利体 | $\it{Sample}$ | `\Bbb` | 黑板粗体 | $\Bbb{SAMPLE}$ |
364 | | `\bf` | 粗体 | $\bf{Sample}$ | `\mit` | 数学斜体 | $\mit{SAMPLE}$ |
365 | | `\sf` | 等线体 | $\sf{Sample}$ | `\scr` | 手写体 | $\scr{SAMPLE}$ |
366 | | `\tt` | 打字机体 | $\tt{Sample}$ |
367 | | `\frak` | 旧德式字体 | $\frak{Sample}$ |
368 |
369 | 指定字体的方式很简单,我们只需要在数学公式中以`{\字体{Sample}}`的形式使用上述字体标记,就可以将“Sample”这几个字符设置为指定字体了。除此之外,在必要情况下,我们还可以使用`\color`标记来指定这些字体的颜色,该标记的第一个参数为颜色的名称,第二个参数是被指定颜色的字符,譬如`$\color{black}{Sample}$`,就是将“Sample”这几个字符设置为`black`这个颜色(当然,这些颜色主要是面向Web浏览器的,对印刷品没有多大的意义)。在这里,可供我们选择的颜色如下:
370 |
371 | | 颜色名称 | 显示效果 | 颜色名称 | 显示效果 |
372 | |:------:|:------------------------:|:-------:|:-------------------------:|
373 | | black | $\color{black}{Sample}$ | grey | $\color{grey}{Sample}$ |
374 | | silver | $\color{silver}{Sample}$ | white | $\color{white}{Sample}$ |
375 | | maroon | $\color{maroon}{Sample}$ | red | $\color{red}{Sample}$ |
376 | | yellow | $\color{yellow}{Sample}$ | lime | $\color{lime}{Sample}$ |
377 | | olive | $\color{olive}{Sample}$ | green | $\color{green}{Sample}$ |
378 | | teal | $\color{teal}{Sample}$ | auqa | $\color{auqa}{Sample}$ |
379 | | blue | $\color{blue}{Sample}$ | navy | $\color{navy}{Sample}$ |
380 | | purple | $\color{purple}{Sample}$ | fuchsia | $\color{fuchsia}{Sample}$ |
381 |
382 | #### 4.2.3.2 运算符
383 |
384 | 在了解了数学公式中所用的字母之后,接下来就可以关注公式中的运算符了。在这些运算符中,除了加减法以及上一节中介绍的乘方、开方、分式、矩阵这些具有特定结构的运算符之外,其它各种运算的符号基本也都有特定的$\LaTeX$标记。下面,我们继续来介绍一些常见的数学符号及其用法。
385 |
386 | ##### 对数运算
387 |
388 | 在数学中,对数运算是指数运算(即乘方运算)的逆运算,为最常见的数学运算之一,下面我们来演示一下如何用$\LaTeX$标记来描述该运算,首先是该运算的运算符:
389 |
390 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
391 | |:---------:|:------:|:--------:|:-------:|:---------:|:------:|
392 | | `\log` | $\log$ | `\lg` | $\lg$ | `\ln` | $\ln$ |
393 |
394 | 接下来,我们就可以试着来编写一些常见的对数运算公式:
395 |
396 | | 公式名称 | 公式编码 | 显示效果 |
397 | |:-------:|:------------------------------------------:|:----------------------------------------:|
398 | | 自然对数 | `$\ln a$` | $\ln a$ |
399 | | 常用对数 | `$\lg a$` | $\lg a$ |
400 | | 和差公式 | `$\log_{a} MN=log_{a} M+log_{a} N$` | $\log_{a} MN=log_{a} M+log_{a} N$ |
401 | | 互换公式 | `$M^{\log_{a} N}=N^{log_{a} M}$` | $M^{\log_{a} N}=N^{log_{a} M}$ |
402 | | 换底公式 | `$\log_{a} N=\frac{\log_{b}N}{log_{b} a}$` | $\log_{a} N=\frac{\log_{b}N}{log_{b} a}$ |
403 |
404 | ##### 三角运算
405 |
406 | 三角形是平面几何的基础,它有着一套独特的数学表示方法。现在,我们要来看看如何用$\LaTeX$标记来表述这套表示方法。同样的,首先是一些符号的标记:
407 |
408 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
409 | |:----------:|:----------:|:--------:|:-------:|:----------:|:----------:|
410 | | `30^\circ` | $30^\circ$ | `\bot` | $\bot$ | `\angle A` | $\angle A$ |
411 | | `\sin` | $\sin$ | `\cos` | $\cos$ | `\tan` | $\tan$ |
412 | | `\csc` | $\csc$ | `\sec` | $\sec$ | `\cot` | $\cot$ |
413 |
414 | 接下来,我们用A、B、C来表示三角形的三条边,用$\alpha$、$\beta$、$\gamma$来表示三角形的三个角,并以R为三角形外接圆的半径来示范一下三角形问题的描述:
415 |
416 | | 公式名称 | 公式编码 | 显示效果 |
417 | |:-------:|:------------------------------------------:|:----------------------------------------:|
418 | | 三角之和 | `$\alpha+\beta+\gamma=180^\circ$` | $\alpha+\beta+\gamma=180^\circ$ |
419 | | 正弦定理 | `$\frac{A}{\sin\alpha}=\frac{B}{\sin\beta}=\frac{C}{\sin\gamma}=2R$` | $\frac{A}{\sin\alpha}=\frac{B}{\sin\beta}=\frac{C}{\sin\gamma}=2R$ |
420 | | 余弦定理 | `$C^2=A^2+B^2-2AB*\cos\alpha$` | $C^2=A^2+B^2-2AB*\cos\alpha$ |
421 |
422 | ##### 比较运算
423 |
424 | 比较运算也是数学的一个重要分支,它在计算机程序设计领域中都有着重要的作用。我们在描述算法等问题时也都会需要表述比较运算。该运算除了`>`、`<`、`=`这些可直接从键盘输入的运算符之外,也有一些运算符是需要用$\LaTeX$标记来表示的:
425 |
426 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
427 | |:----------:|:----------:|:------------:|:------------:|:-------------:|:-------------:|
428 | | `\not<` | $\not<$ | `\not>` | $\not>$ | `\not=` | $\not=$ |
429 | | `\le` | $\le$ | `\ge` | $\ge$ | `\approx` | $\approx$ |
430 | | `\equiv` | $\equiv$ |
431 |
432 | 下面照例来做几个演示:
433 |
434 | | 运算编码 | 显示效果 |
435 | |---------------------------------------|--------------------------------------|
436 | | `if $a \not< b$, then $a \ge b$.` | if $a \not< b$, then $a \ge b$. |
437 | | `if $a \not> b$, then $a \le b$.` | if $a \not> b$, then $a \le b$. |
438 | | `if $a \approx b$, then $a \not= b$.` | if $a \approx b$, then $a \not= b$. |
439 |
440 | ##### 集合运算
441 |
442 | 集合运算是离散数学的基础,在计算机科学领域有着非常重要的作用,我们在写计算机论文时少不了要描述这类运算,下面是一些集合运算符的$\LaTeX$标记:
443 |
444 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
445 | |:-----------:|:-----------:|:------------:|:------------:|:-------------:|:-------------:|
446 | | `\emptyset` | $\emptyset$ | `\in` | $\in$ | `\notin` | $\notin$ |
447 | | `\subset` | $\subset$ | `\supset` | $\supset$ | `\subseteq` | $\subseteq$ |
448 | | `\supseteq` | $\supseteq$ | `\cap` | $\cap$ | `\cup` | $\cup$ |
449 | | `\bigvee` | $\bigvee$ | `\bigwedge` | $\bigwedge$ | `\biguplus` | $\biguplus$ |
450 | | `\forall` | $\forall$ | `\exists` | $\exists$ | `\not\subset` | $\not\subset$ |
451 |
452 | 在这里,我们可以用上述标记来编写几条集合运算的基本法则,以作演示:
453 |
454 | | 公式名称 | 公式编码 | 显示效果 |
455 | |:-------:|:------------------------------------------:|:----------------------------------------:|
456 | | 同一律 | `$A \cup \emptyset =A$` | $A \cup \emptyset =A$ |
457 | | 交换律 | `$A \cap B=B \cap A$` | $A \cap B=B \cap A$ |
458 | | 结合律 | `$(A \cup B) \cup C=A \cup (B \cup C)$` | $(A \cup B) \cup C=A \cup (B \cup C)$ |
459 | | 分配律 | `$(A \cap B) \cup C=(A \cup C ) \cap (B \cup C)$` | $(A \cap B) \cup C=(A \cup C ) \cap (B \cup C)$ |
460 |
461 | ##### 微积分运算
462 |
463 | 微积分是高等数学的入门学科,内容主要包括极限、微分学、积分学及其应用。下面是我们在描述微积分运算时会用到的一些$\LaTeX$标记:
464 |
465 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
466 | |:----------:|:----------:|:--------:|:-------:|:----------:|:----------:|
467 | | `\int` | $\int$ | `\iint` | $\iint$ | `\iiint` | $\iiint$ |
468 | | `\iiiint` | $\iiiint$ | `\oint` | $\oint$ | `\prime` | $\prime$ |
469 | | `\lim` | $\lim$ | `\infty` | $\infty$ | `\nabla` | $\nabla$ |
470 |
471 | 我们不妨在这里复习一下当年在大学一年级时写过的那些公式,只不过当时应该是手写为主,现在我们要用的是$\LaTeX$标记:
472 |
473 | | 公式名称 | 公式编码 | 显示效果 |
474 | |:-------:|:------------------------------------------:|:--------------------------------------------:|
475 | | 不定积分 | `$\int f(x) {\rm{d} x}$` | $\int f(x) {\rm{d} x}$ |
476 | | 定积分 | `$\int^b_a f(x) {\rm{d} x}$` | $\int^b_a f(x) {\rm{d} x}$ |
477 | | 微分方程 | `$\frac{{\rm{d} x(t}}{x(t)}}=f(x) {\rm{d} x}$` | $\frac{{\rm{d}x(t)}}{x(t)}=f(x) {\rm{d} x}$ |
478 | | 极限运算 | `$\lim_{n \to \infty} \frac{1}{n(n-1)}$` | $\lim_{n \to \infty} \frac{1}{n(n-1)}$ |
479 |
480 | 当然,除上述运算外,我们在描述数学问题过程中还可能会用到如下这些运算符:
481 |
482 | | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 | 运算符标记 | 显示效果 |
483 | |:----------:|:----------:|:------------:|:------------:|:-------------:|:-------------:|
484 | | `\pm` | $\pm$ | `\times` | $\times$ | `\div` | $\div$ |
485 | | `\mid` | $\mid$ | `\nmid` | $\nmid$ | `\cdot` | $\cdot$ |
486 | | `\circ` | $\circ$ | `\ast` | $\ast$ | `\bigodot` | $\bigodot$ |
487 | | `\bigotimes` | $\bigotimes$ | `\bigoplus` | $\bigoplus$ | `\sum` | $\sum$ |
488 | | `\prod` | $\prod$ | `\coprod` | $\coprod$ | `\backslash` | $\backslash$ |
489 | | `\because` | $\because$ | `\therefore` | $\therefore$ |
490 |
491 | 这些$\LaTeX$标记的使用与上述运算大同小异,这里就不一一示范了,读者可自行查阅相关文档。
492 |
493 | #### 4.2.3.3 定界符
494 |
495 | 在数学公式中,除了参与运算的字母变量、数字以及表明运算类型的运算符之外,以括号为代表的定界符也是一类非常重要的符号。众所周知,数学公式的编辑是离不开各种各样的括号的,我们需要用它们来凸显公式中的重点、对公式进行分组、甚至改变公式的运算顺序。在$\LaTeX$中,括号是由开符号和闭符号组成的,所以我们要分两个标记来表列$\LaTeX$所提供的括号种类,具体如下:
496 |
497 | | 括号类型 | 开符号 | 闭符号 | 示例编码 | 显示效果 |
498 | |---------|---------------|---------------|---------------------------|-------------------------|
499 | | 圆括号 | `(` | `)` | `$a+(b-c)$` | $a+(b-c)$ |
500 | | 方括号 | `[` | `]` | `$a+[b-c]$` | $a+[b-c]$ |
501 | | 花括号 | `\lbrace` | `\rbrace` | `$a+\lbrace b-c \rbrace$` | $a+\lbrace b-c \rbrace$ |
502 | | 尖括号 | `\langle` | `\rangle` | `$a+\langle b-c \rangle$` | $a+\langle b-c \rangle$ |
503 | | 向上取整 | `\lceil` | `\rceil` | `$a+\lceil b-c \rceil$` | $a+\lceil b-c \rceil$ |
504 | | 向下取整 | `\lfloor` | `\rfloor` | `$a+\lfloor b-c \rfloor$` | $a+\lfloor b-c \rfloor$ |
505 |
506 | 由于数学结构的关系,我们有时候会希望括号的大小是可以随着公式结构变化的。为实现这个效果,我们需要在括号的开符号之前加上`\left`标记,闭符号之前加上`\right`标记。例如,对于下面这个公式:
507 |
508 | > $$
509 | > \alpha_x \alpha_y \left[ \frac{1}{3} \left( x^2+y^{\left( 2x-y \right)} \right)^2 + xy \right]
510 | > $$
511 |
512 | 我们需要在Markdown文档中输入如下编码:
513 |
514 | ```Markdown
515 | $$
516 | \alpha_x \alpha_y \left[ \frac{1}{3} \left( x^2+y^{\left( 2x-y \right)} \right)^2 + xy \right]
517 | $$
518 | ```
519 |
520 | 请注意,`\left`和`\right`这两个标记必须要位于同一逻辑行中,否则就无法配对,但它们所配对的定界符不一定是括号,甚至一个句点也可以的。当然,定界符也并非只有括号这种配对的符号,如下公式中的竖线和斜线也都属于定界符:
521 |
522 | | 定界符 | 公式编码 | 显示效果 |
523 | |:------------:|:---------------------------------:|:--------------------------------------------:|
524 | | `/` | `$f(x) / x-1$` | $f(x) / x-1$ |
525 | | `\backslash` | `$f(x) \backslash x-1$` | $f(x) \backslash x-1$ |
526 | | `\vert` | `$f(x) \vert x-1$` | $f(x) \vert x-1$ |
527 | | `\Vert` | `$f(x) \Vert x-1$` | $f(x) \Vert x-1$ |
528 |
529 | 对这种不成对的单一定界符,我们也可以使用`\middle`标记令其根据公式的结构调整自身大小。例如,对于下面这个公式:
530 |
531 | > $$
532 | > \Pr \left( X>\frac{1}{3} \middle\vert Y=0 \right) = \left. \int_0^1 p(t)\, \rm{d}t \middle/ (N^2+1) \right.
533 | > $$
534 |
535 | 我们只需要在Markdown文档中输入如下编码:
536 |
537 | ```Markdown
538 | $$
539 | \Pr \left( X>\frac{1}{3} \middle\vert Y=0 \right) = \left. \int_0^1 p(t)\, \rm{d}t \middle/ (N^2+1) \right.
540 | $$
541 | ```
542 |
543 | ### 4.2.4 多行公式
544 |
545 | 如果我们在撰写科学性文章时讨论的数学问题都是用行内公式,或者单行的行间公式就能表述的,那么即使用Office Word中的相关工具来编辑这些公式也不是一件多么让人不可接受的事情。但现实是残酷的,哪怕我们要演示一个开方运算的过程,其演算列表也少不了要连续写个五六行,更何况我们还会遇到长度足以需要换行的长公式,以及根据参数条件分组的条件公式。只有在编写这些公式时,我们才能真正体会到$\LaTeX$的强大。在这一节中,我们就来讨论一下多行公式的编辑。
546 |
547 | 和矩阵一样,多行公式在$\LaTeX$中也被视为一个独立的排版单元。所以,我们首先需要用单元定义标记`\begin`和`\end`定义一个公式单元。同样的,在定义公式单元时也需要指定该单元的样式,我们最常用的公式样式有两种:
548 |
549 | - 第一种是`gather`,在这种样式下,公式单元中的所有公式都会居中对齐,这也是普通的样式。例如,如果想撰写下面这样的一个三元线性方程组:
550 |
551 | > $$
552 | > \begin{gather}
553 | > \alpha_{11}x+\alpha_{12}y+\alpha_{13}z=A \\
554 | > \alpha_{21}x+\alpha_{22}y+\alpha_{23}z=B \\
555 | > \alpha_{31}x+\alpha_{32}y+\alpha_{33}z=C \\
556 | > \end{gather}
557 | > $$
558 |
559 | 我们就可以在Markdown文档中输入如下编码:
560 |
561 | ```Markdown
562 | $$
563 | \begin{gather}
564 | \alpha_{11}x+\alpha_{12}y+\alpha_{13}z=A \\
565 | \alpha_{21}x+\alpha_{22}y+\alpha_{23}z=B \\
566 | \alpha_{31}x+\alpha_{32}y+\alpha_{33}z=C \\
567 | \end{gather}
568 | $$
569 | ```
570 |
571 | - 第二种是`align`,它会让公式单元中的所有公式按用`&`符指定的符号对齐。例如,如果想撰写下面这样的一个演算列表:
572 |
573 | > $$
574 | > \begin{align}
575 | > \sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
576 | > &= \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
577 | > &= \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
578 | > &= \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
579 | > &\approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
580 | > \end{align}
581 | > $$
582 |
583 | 我们就需要使用`align`样式,令其按等号对齐,具体编码如下:
584 |
585 | ```Markdown
586 | $$
587 | \begin{align}
588 | \sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
589 | &= \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
590 | &= \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
591 | &= \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
592 | &\approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
593 | \end{align}
594 | $$
595 | ```
596 |
597 | 当然,我们还可以使用`flalign`和`alignat`这两种样式,使用方式大同小异,读者可以自行查阅相关文档。下面,我们来看看如何撰写按条件分组的公式。事实上,这种公式的写法就是在一个单行的公式中嵌套一个样式为`cases`的多行公式单元。例如,如果想撰写这样一个按奇偶数分组的公式:
598 |
599 | > $$
600 | > f(n) =
601 | > \begin{cases}
602 | > n/2, & \text{若$n$为偶数} \\
603 | > 3n+1, & \text{若$n$为奇数} \\
604 | > \end{cases}
605 | > $$
606 |
607 | 我们就只需要在Markdown文档中输入如下编码即可:
608 |
609 | ```Markdown
610 | $$
611 | f(n) =
612 | \begin{cases}
613 | n/2, & \text{若$n$为偶数} \\
614 | 3n+1, & \text{若$n$为奇数} \\
615 | \end{cases}
616 | $$
617 | ```
618 |
619 | 同样的,`cases`只是分组公式单元最常见的一种样式,如果我们能引入`mathtools`宏组的话,还能使用`gathered`、`aligned`、`alignedat`、`multlined`等样式,它们的使用方式也大同小异,读者可以自行查阅相关文档,这里就不一一累述了。
620 |
621 | 在研究完如何罗列多个公式之后,让我们最后再来回头关心一下应该如何将单一公式分行显示。其实分行显示一个公式的方法也非常简单,就是先将公式单元定义为`gather`、`align`等样式,然后在编辑公式过程中,用`\\`来分行即可。例如,如果想撰写下面这样的一个公式:
622 |
623 | > $$
624 | > \begin{align}
625 | > a&+b+c+d+e \\
626 | > &+f+g+h+i \\
627 | > &+j+k+l+m \\
628 | > &+n+o+p+q \\
629 | > &+r+s+t+u \\
630 | > &+v+w+x+y+z
631 | > \end{align}
632 | > $$
633 |
634 | 我们只需要在Markdown文档中输入如下编码即可:
635 |
636 | ```Markdown
637 | $$
638 | \begin{align}
639 | a&+b+c+d+e \\
640 | &+f+g+h+i \\
641 | &+j+k+l+m \\
642 | &+n+o+p+q \\
643 | &+r+s+t+u \\
644 | &+v+w+x+y+z
645 | \end{align}
646 | $$
647 | ```
648 |
649 | ## 本章小结
650 |
651 | 在这一章中,我们首先介绍了$\LaTeX$这门专用于排版的标记语言,包括它的前世今生,基本语法形式,以及如何在Markdown文档中使用$\LaTeX$标记。然后,我们分公式结构、公式符号以及多行公式编辑三个主题详细而深入地介绍了如何在Markdown文档中表述数学问题。
652 |
653 | 到目前为止,Markdown在写作阶段的应用就基本介绍完了。在接下来的内容中,我们将介绍如何将Markdown文档转换成`docx`、`PDF`等主流的文档格式,或者制作成电子书或博客分享给读者,以及如何与合作者进行线上协作,同步修改,并在修改过程中完成文档的版本控制。
654 |
655 |
656 |
657 | [^1]:注释:高德纳教授是现代计算机科学的先驱人物,他创立了算法分析理论,并在数个计算机理论分支上都做出了犹如基石一般的贡献,于1974年荣获图灵奖。
658 | [^2]:注释:莱斯利·兰伯特是来自纽约的一位计算机科学家,$\LaTeX$排版系统的开发者,2013年荣获图灵奖。
659 | [^3]:注释:官方网站:https://www.mathjax.org
660 | [^4]:注释:amsmath宏组是LaTeX中最常用的组件之一,由美国数学协会(AMS)设计开发,它全面扩展了LaTeX的数学表述能力,目前已经成为了LaTeX中的必备组件。
--------------------------------------------------------------------------------
/src/05_第五章.md:
--------------------------------------------------------------------------------
1 | # 第5章 作品的审阅与维护
2 |
3 | ## 本章提要
4 |
5 | 我写这本书的目的之一,就是想阐述一种“像写程序一样写作”的方法论。在我个人看来,写作和写程序代码在本质上并没有多少差异,两者的首要工作都应该是用语言工具将问题或观点表达清楚,然后在表达清晰的基础上,我们再来追求一些表达的效率。该简单明了的地方,不要拐弯抹角、废话连篇,该突出重点的地方不要语焉不详、故弄玄虚。最后才是追求美感,锦上添花。在很多时候,作品的成功在于知道如何在设计上做减法,而不是盲目地往里添加各种其实并没有什么用的东西。
6 |
7 | 另一方面,和程序中始终会存在bug一样,我们在写作时表达中也始终会存在各种各样的问题,有些是表达逻辑上的缺陷,有些是表达视角上的问题,甚至还有些只是一些语病、错别字问题。我们可能写不出没有bug的程序和没有问题的文章,但可以一直持续地完善自己的作品,优秀的文章和优秀的程序一样,来自于写完之后的精心打磨和维护,在这一章中,我们将继续以之前的论文为导引,讨论一下Markdown文档的审阅、修改与维护。
8 |
9 | ## 5.1 选择合适的审阅工具
10 |
11 | 在一件作品完成之后,其质量的第一个把关者通常都应该是作者自己。每一个作者在写作过程中,多多少少都会存在一些输入性错误(相当于纸和笔时代的笔误),他们应该尽可能地找出作品中错误的文字、标点、代码以及图表。除此之外,我们的作品中通常还少不了会存在一些词不达意、表达不够充分的,甚至是表达错误,存在语病的文字。最后,作品本身的结构,譬如章节的先后顺序可能也需要做一些调整。所有的这一切,都是我们在自我检阅过程中要完成的任务。
12 |
13 | 要想较好地完成自我检阅工作,我们首先要做的就是通读自己的作品。在通读过程中,我们应该尽可能地专注于作品本身的内容,这时候任何与作品内容无关的事物都应被视为干扰,即使是最简单的Markdown标记也不例外。为了在通读作品时排除这些干扰,最简单直接的做法就是使用Markdown的预览器来完成通读工作。但这种做法有一个明显的缺陷:这些预览器只能显示Markdown标记的渲染效果,它们并不支持文章的直接修改。也就是说,每当我们发现作品中存在问题时,就要去编辑器中找到该问题所在的相应位置才能修改,这终归让人感觉没有Microsoft Word那样做到“所见即所得”的使用体验。所以在这里,我会建议大家使用同样实现了“所见即所得”的Typora编辑器来完成作品检阅阶段的工作。下面,我们就来介绍一下这款编辑器的具体使用。让我们先从利用这款编辑器的优势开始:
14 |
15 | 首先,当然是这款编辑器的**跨平台特性**。Typora支持MacOS、Windows以及各种Linux桌面发行版,我们可以在各种工作环境中使用这款编辑器,不受具体操作系统的限制。譬如,我的台式机上运行的是Ubuntu,而我的笔记本电脑是Macbook Air,它运行的是MacOS,我通常会在不同的时间段里分别在这两台电脑上对相同的文章进行编辑,Typora在两边的用户体验是完全一致的,完全感觉不到使用环境的不同。下面,我们就来简单介绍一下如何在MacOS、Windows和Ubuntu这三个系统中如何下载安装Typora吧。
16 |
17 | Typora在MacOS和Windows下的安装过程极为简单,其步骤如下:
18 |
19 | - 第一步. 在浏览器中打开下载地址: `https://typora.io/`
20 | - 第二步. 在打开的页面中找到如下图所示的下载链接,下载相应系统的安装包,并根据安装向导完成安装即可。
21 |
22 | 
23 |
24 | *请注意*:MacOS的版本需在10.10以上。
25 |
26 | 而该编辑器在Ubuntu上的安装则更复杂一点,我们需要使用apt包管理器来安装(当然你也可以直接下载二进制安装包),这样做的好处是,今后我们可以直接使用apt命令来进行软件更新,其步骤如下:
27 |
28 | - 第一步. 在浏览器中打开相关下载页面: `https://typora.io/#linux`
29 | - 第二步. 复制页面中显示的`shell`命令,并在终端中执行。
30 |
31 | ```bash
32 | # or run:
33 | # sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE
34 | wget -qO - https://typora.io/linux/public-key.asc | sudo apt-key add -
35 |
36 | # add Typora's repository
37 | sudo add-apt-repository 'deb https://typora.io/linux ./'
38 | sudo apt-get update
39 |
40 | # install typora
41 | sudo apt-get install typora
42 | ```
43 |
44 | *请注意*:上述下载页面也提供了二进制安装包的下载链接,其位于上面这段`shell`代码的正下方,显示为`>> or,download binary file x63 x86`字样。
45 |
46 | 然后是最重要的**即时预览**功能。Markdown编辑器常见的界面布局通常都是并列着两个窗口,左边为编码区,用于编写Markdown标记源码,右边则是预览区,用于显示相应的`HTML`渲染效果。在写作过程中,为了及时掌握标记的作用,在编写源码时同步查看一下渲染效果是可以接受的,因为有些标记的复杂应用(譬如制作图表,编写数学公式)还是需要我们在专注于标记本身的编码,但如果到了自我检阅阶段,需要专注于作品内容时这种安排就确实让人觉得有些不便了,这时候Typora的即时渲染功能,所见即所得的优势就凸显了出来。下面是该编辑器打开之前那篇论文第2章时的效果:
47 |
48 | 
49 |
50 | 接下来是其支持的**扩展功能**:Typora主要支持的是`GitHub Flavored Markdown(GFM)`风格的语法,并提供了任务列表、表情符号、数学公式、代码高亮、图表生成等扩展支持,当然,部分扩展在默认设定下是没有被打开的,我们需要通过依次点击「文件-偏好设置」菜单,打开设置界面,在如下界面中勾选相关选项:
51 |
52 | 
53 |
54 | 在设置完成之后,我们就可以来看看该编辑器对于这些扩展的支持情况,譬如下面是$\LaTeX$数学公式和`Mermaid`图库生成的渲染效果:
55 |
56 | 
57 |
58 | 当我们将光标移动到相关元素上时,编辑器就会自动显示该公式和图形元素背后的Markdown标记,我们可以随时就发现的问题对它们进行修改。譬如下面是修改序列图时的状态:
59 |
60 | 
61 |
62 | 除此之外,Typora还对几乎所有的Markdown语法都提供了**快捷操作**,我们可通过「段落」和「格式」这两个菜单中的选项来快速设置Markdown文档中的元素标记。当然,在我们足够熟练之后,还可以通过这些菜单项旁边标注的快捷键来进行更为高效的操作。而在阅读体验方面,Typora不仅界面设计得简约美观,还默认自带了6种Markdown的**预览主题**,我们可通过「主题」菜单进行随意切换,以进一步改善我们的阅读体验。譬如,下面是以`Newsprint`主题来显示上述论文第2章时的效果;
63 |
64 | 
65 |
66 | ## 5.2 转换成更通用的格式
67 |
68 | 当然,一部作品仅仅靠自我审阅是远远不够的,因为每个作者都有其自身的思考盲区,总有一些问题靠他自己是发现不了的。所以下一步就是要找若干个可靠的人来对作品进行更细致而广泛地审阅或试读,并根据他们的反馈来进行更进一步的修改。这时候,我们就必须要解决一个问题,那就是,*作品要以什么格式分发给我们的审阅者或试读者?*
69 |
70 | ### 5.2.1 目标格式与转换工具
71 |
72 | 要想解决这个问题,我们就得先来想一想参与作品审阅或试读的会是哪一些人。譬如,我们在这里用来举例的是一篇本科生的毕业论文,它的审阅者或试读者可能就是同专业的同学,以及直接指导这篇论文的老师,当然也有可能会有一些愿意帮助你完成论文的热心网友。虽然Markdown文档本身纯文本的特性很适合用来做分发和传阅,但我们必须考虑Markdown的实际普及情况,对于很多人来说,Markdown可能还完全是一个陌生事物,我们不能在邀请别人审阅或试读自己作品的时候跟他说:“嗨,你应该先了解一下Markdown语法,还有,最好先安装一个叫做Typora的编辑器”。何况这些人中可能还有我们的老师和前辈。所以,更合适的做法是将Markdown文档视为作品的源文件,然后像使用程序源代码一样用编译器或解释器输出用户可以直接使用的文档格式。
73 |
74 | 对于程序来说,这种文档格式应该是一些二进制的可执行文件(譬如Windows下的`.exe`或`.dll`文件)。但对于文字作品来说,这种文档格式应该是怎么样的呢?首先,它应该是一种主流的跨平台文档格式,也就是说,这种格式的文档应该在所有主流操作系统上都只需要通过简单安装一款软件就能直接打开,并且这款软件应该是大多计算机用户都会安装,且是日常都在使用的,不需要进行复杂的系统配置。其次,这种格式的文档应该带给用户良好且一致的阅读体验。它应该像印刷品一样有美观的排版,将平台因素对文档呈现效果的影响降到最低。最后,这种文档格式应该要支持一定的批阅功能,以便读者在对作品提出审阅意见的同时不必修改文档本身的内容。综合以上要求,我们就会发现,目前最能满足需求的应该就只有`PDF`和`docx`这两种文档格式了。
75 |
76 | 在确定了目标文档格式之后,接下来的问题是,我们要用什么工具来做格式转换呢?换而言之,将Markdown文档输出成目标格式的“编译器”或“解释器”是什么呢?事实上,这个问题我们可以在Typora编辑器上找到答案。在该编辑器的「文件-导出」菜单中,我们可以看到它支持将Markdown文档导出哪些格式,但在点击你要导出的格式之后(譬如`docx`),它会提示你这些功能需要先安装Pandoc。这就是我们要使用的转换工具。
77 |
78 | ### 5.2.2 Pandoc的安装与使用
79 |
80 | Pandoc是一款用`Haskell`语言实现的著名的标记语言转换工具。该工具支持多种操作系统平台,采用命令行交互界面,主要用于执行不同标记语言之间的格式转换,堪称文档处理领域中的“瑞士军刀”。在本节,我们就来详细介绍一下这款工具的安装与使用。
81 |
82 | 首先,我们需要根据自己所在的操作系统平台来安装Pandoc(如果需要用它将相关格式转换成`PDF`文件的话,还必须同时安装$\LaTeX$组件)。正如上面所说,Pandoc支持几乎所有的操作系统,我们在这里照例以Windows、MacOS和Ubuntu三个系统为例来介绍Pandoc的安装步骤。
83 |
84 | 首先是在Windows下,其安装步骤如下:
85 |
86 | - 步骤1. 在浏览器中打开下载页面:`https://github.com/jgm/pandoc/releases/latest`
87 | - 步骤2. 下载最新的安装包:pandoc-<版本号>-windows.msi
88 | - 步骤3. 双击安装包后按照向导提示一步步完成安装
89 | - 步骤4. 设置好Pandoc的环境变量
90 |
91 | 接着是在MacOS下,Pandoc有两种安装方式:
92 |
93 | 1. 二进制安装包:
94 | - 步骤1. 在浏览器中打开下载页面:`https://github.com/jgm/pandoc/releases/latest`
95 | - 步骤2. 下载最新的二进制安装包: pandoc-<版本号>-osx.pkg
96 | - 步骤3. 双击安装包后按照向导提示一步步完成安装
97 |
98 | 2. homebrew包管理器,这种方式只需要在终端中执行以下命令即可:
99 |
100 | ```bash
101 | sudo brew install pandoc
102 | ```
103 |
104 | 最后,在Ubuntu下,Pandoc的安装方式也有两种:
105 |
106 | 1. 二进制安装包:
107 | - 步骤1. 在浏览器中打开下载页面:`https://github.com/jgm/pandoc/releases/latest`
108 | - 步骤2. 下载最新的二进制安装包: pandoc-<版本号>-amd64.deb
109 | - 步骤3. 双击安装包后按照向导提示一步步完成安装
110 |
111 | 2. apt包管理器,这种方式只需要在终端中执行以下命令即可:
112 |
113 | ```bash
114 | sudo apt-get install pandoc
115 | ```
116 |
117 | 除此之外,我们在所有的操作系统中都可以选择先安装`Haskell`平台,然后使用其中的cabal工具来安装Pandoc,其命令如下:
118 |
119 | ```bash
120 | cabal update
121 | cabal install pandoc
122 | ```
123 |
124 | 在完成安装之后,可以在终端中输入`pandoc -v`来查看我们所安装的版本,只要看到类似于下面这样的输出,就说明Pandoc安装成功了:
125 |
126 | 
127 |
128 | 在确认安装了Pandoc之后,接下来就可以开始使用Pandoc了。我们先来看看Pandoc到底支持哪一些标记语言:
129 |
130 | | Pandoc可读取的源格式 | Pandoc可生成的目标格式 |
131 | |-----------------------|-------------------------------------------------------------------------------|
132 | | Markdown | HTML格式:包括XHTML,HTML5及HTML slide。 |
133 | | reStructuredText | 文字处理软件格式:包括docx、odt、OpenDocument XML。 |
134 | | textile | 电子书格式:包括EPUB(第2版及第3版)、FictionBook2 |
135 | | HTML | 技术文档格式:包括DocBook、GNU TexInfo、Groff manpages、Haddock。 |
136 | | DocBook | 页面布局格式:InDesign ICML。 |
137 | | LaTeX | 大纲处理标记语言格式:OPML。 |
138 | | MediaWiki标记语言 | TeX格式:包括LaTeX、ConTeXt、LaTeX Beamer。 |
139 | | OPML | PDF格式:需要LaTeX支持。 |
140 | | Org-Mode | 轻量级标记语言格式:包括Markdown、reStructuredText、textile、Org-Mode、MediaWiki标记语言、AsciiDoc。|
141 | | Haddock | 自定义格式:可使用lua自定义转换规则。 |
142 |
143 | 或许,上述表格中列出的很多格式可能都让人觉得很陌生,但这没有关系,我们在这里的主要目标就是将Markdown文档转换成`PDF`和`docx`格式,并不需要你掌握Pandoc支持的所有文档格式。下面,我们就先来看看如何用Pandoc将Markdown文档输出为Microsoft Word文档(即`docx`格式)。
144 |
145 | 通过在终端中输入`pandoc -h`,我们可以了解到Pandoc命令的基本格式如下:
146 |
147 | > pandoc [options] [input-file] ...
148 |
149 | 并且有以下常用选项:
150 |
151 | | 选项 | 含义 |
152 | |---------------------|----------------------------------------------------------------------------------|
153 | | `-f FORMAT`, `-r FORMAT`, `--from=FORMAT`, `--read=FORMAT` | 指定输入文件的格式,若不指定,pandoc可以从明显的文件后缀名中推测,若无明显提示,默认的输入文件格式是Markdown,默认的输出文件格式是`HTML`。 |
154 | | `-t FORMAT`, `-w FORMAT`, `--to=FORMAT`, `--write=FORMAT` | 指定输出文件的格式。 |
155 | | `-o FILE`, `--output=FILE` | 写输出到FILE文件而不是到标准输出。 |
156 | | `--list-input-formats` | 列出支持的输入文件格式。 |
157 | | `--list-output-formats` | 列出支持的输出文件格式。 |
158 | | `--list-extensions` | 列出支持的Markdown扩展,+代表默认支持,-代表默认不支持。 |
159 | | `-s`, `--standalone` | 产生输出文件时附带适当的头注和脚注(比如`HTML`)。 |
160 | | `-c URL`, `–css=URL` | 链接到`CSS`样式表。该选项能够使用多次来引入多个文件,所指定的文件能够以指定的顺序依次引入。|
161 |
162 | 所以根据帮助信息中给出的说明,如果要想将Markdown文档转换为Microsoft Word文档,我们需执行如下命令:
163 |
164 | ```bash
165 | pandoc input.md -o output.docx -c Github.css
166 | ```
167 |
168 | 在这里,input.md是输入文件,`-o`选项后面跟的参数代表的输出文件,即output.docx,`-c`选项指定的是Markdown文档的渲染样式,这里选择的是Github的样式。另外,如果我们在Markdown文档中使用了$\LaTeX$标记,那就还需要在上述命令的后面再加上一个`--latex-engine=xelatex`参数,以用来指定$\LaTeX$引擎。
169 |
170 | 在通常情况下,Pandoc会根据文件的后缀名自动判断格式。当然,我们也可以显式地指定输入文件和输出文件格式,譬如:
171 |
172 | ```bash
173 | pandoc -f markdown -t docx input.md -o output.docx -c Github.css
174 | ```
175 |
176 | 在上述命令中,`-f`选项代表的是输入文件的格式,这里指定了markdown。而`-t`选项代表的则是输出文件的格式,这里指定的是`docx`。读到这里,有过编译C/C++或Java程序经验的读者肯定已经发现了,Pandoc的使用方式与我们曾经使用过的gcc、javac等编译器是非常类似的。这意味着,我们也可以使用`makefile`这样的项目配置文件来管理Markdown项目的输出,真正实现像管理程序项目一样管理我们的写作项目,譬如,下面是我为自己论文项目编写的一个`makefile`文件,它会根据我修改的Markdown文档来更新输出的Microsoft Word文档:
177 |
178 | ```makefile
179 | # 时间:2019年04月22日
180 | # 作用:将markdown文件转换成docx格式
181 |
182 | src = $(shell find ./ -name "*.md")
183 | docx = $(src:%.md=../docx/%.docx)
184 |
185 | all: $(docx)
186 | ls -l ../docx
187 |
188 | ../docx/%.docx:%.md
189 | pandoc -f markdown+tex_math_dollars -t docx $< -o $@ --latex-engine=xelatex
190 |
191 | clean:
192 | rm -rf $(docx)
193 | ```
194 |
195 | 当然,我们需要先像管理程序带一样将上面这个`makefile`文件和所有的Markdown文件一起放入项目的`src`子目录中,然后再创建一个`docx`目录以作为输出目录,最后才能进到`src`目录中执行`make`命令。如果有读者对`makefile`的写法并不熟悉,可以参考我在*附录A:Makefile简易教程*中所做的相关介绍。现在,让我们来看一下生成的`docx`文档:
196 |
197 | 
198 |
199 | 同样地,对于将Markdown文档转成`PDF`格式,我们当然也可以采用类似的方法,只需要将Pandoc命令修改如下即可:
200 |
201 | ```bash
202 | pandoc -f markdown -t pdf input.md -o output.pdf -c Github.css --latex-engine=xelatex -V mainfont=heiti
203 | ```
204 |
205 | 但我们在这里其实可以用一种更简单的方式,即我们在一开始就提到的,Typora编辑器的「文件-导出」菜单。在安装了Pandoc之后,Typora编辑器支持将Markdown文档导出为HTML、PDF、docx、odt、rtf、epub、LaTeX、Media Wiki等格式。譬如,下面是之前论文第2章导出的`PDF`文档:
206 |
207 | 
208 |
209 | 当然,如果你对输出的`PDF`文档在排版时有更细致的要求(譬如想调整图片的大小、实现图文绕排),我们也可以选择先将Markdown文档导出为$\TeX$格式的源文件,在使用$\LaTeX$进行排版处理之后再输出`PDF`格式。
210 |
211 | ## 5.3 使用版本控制系统
212 |
213 | 在完成毕业论文的初稿之后,指导老师往往会针对性地提出各种不同的问题,让我们进行多轮修改,有时候甚至要改上七八稿以上。在这种情况下,我们应该如何管理这篇论文的各个修改版本呢?众所周知,我们通常都是在空间这个维度上对项目进行管理的。毕竟,项目中的源文件(譬如C源码文件、Markdown文件)、输出文件(譬如可执行文件、`PDF`文件)以及配置文件(譬如`makefile`文件)都是以文件和目录的形式存储在磁盘空间上的,但现在我们想要管理的是自己不同时间段里所做的修改,这种时间维度上的项目管理应该怎么做呢?答案就是:使用版本控制系统 (Version Control System)。
214 |
215 | 版本控制系统是一种记录文件修改演化的系统,它的作用就是方便我们找回项目在某个特定时间点(即版本)上的文件、查看这些版本前后都做了哪些修改,并对这些修改进行比对,以修正一些致命性的错误。从版本控制系统的发展历史来看,它主要经历了本地版本控制、集中式版本控制和分布式版本控制三个阶段:
216 |
217 | - **本地版本控制(Local Version Control System)**:这顾名思义就是本地化的版本控制系统,它没有网络协作等较为先进的版本控制的概念。
218 |
219 | - **集中式版本控制(Centralized Version Control System)**:这种版本控制系统通常设置有一台用于执行版本控制服务的中央服务器,这台服务器会一直处于运行状态,由用户上传或下载其项目的各个版本。这类系统在很长一段时间里都是版本控制的主流方式,著名的`CVS`与`SVN`都是这一类版本控制系统的代表。
220 |
221 | - **分布式版本控制(Distributed Version Control System)**:这种版本控制系统解决了集中式版本控制可能因为其中央服务器故障而带来的麻烦,它可以让每一台客户端都完全镜像整个被纳入版本控制的项目。也就是说,在分布式版本控制系统中,任何一台机器都可以视为版本控制服务器。即使有一台服务器失去服务能力,其它服务器还可以继续协作维持版本控制系统的正常运转。
222 |
223 | 对于毕业论文这种个人属性比较强,而又需要与人分享协作的项目来说,显然分布式版本控制系统是比较合适的选择。所以,接下来我们就以时下最流行的分布式版本控制系统——git——为例来介绍一下Markdown项目的管理。
224 |
225 | ### 5.3.1 git简介
226 |
227 | git是林纳斯·托瓦兹(Linus Torvalds)为更好地管理Linux内核开发而设计的一个分布式版本控制软件。这款软件与其它主流版本控制系统最大的区别是:在项目版本更新的过程中,git并没有直接去记录基于初始文件的变化数据,而是通过一系列快照(Snapshot,就像是个小型的文件系统)来保存记录每个文件。在此过程中,对于那些没有发生变化的文件,它们在新版本中就会是一个指向其最近一次更新的链接。此外,几乎所有git的操作都是在本地进行的,所以并不存在服务器”延迟”的问题,几乎所有的操作都是瞬间完成的。例如,如果我们想要查看项目的版本历史,就不必特地去服务器上抓取历史记录了,直接在本地浏览即可。而且,这种几乎完全本地化的操作方式也为许多特殊的应用场景提供了支持,譬如:我们在开发过程中都可能会遇到要在无网络环境中需要对自己的项目进行修改,并同时要用版本控制系统将这些修改记录下来的尴尬场景,这时,git无疑就是最好的选择了。
228 |
229 | 下面我们来简单介绍一下git的存储机制。在git中,我们的项目文件主要有三种状态,它们分别是:
230 |
231 | - **提交**: 在这种状态下,文件或数据已经安全的存放在了git本地数据库中。
232 | - **修改**: 在这种状态下,文件或数据已经修改但是尚未提交到数据库。
233 | - **暂存**: 在这种状态下,文件或数据已被标记要放入到下一次要提交的版本中。
234 |
235 | 为了实现这种不同状态的存储,一个git项目应该要被分成三个组成部分(这里假设我们的项目目录叫`git-repo`):
236 |
237 | - **git目录**: 该目录是存放项目中所有元数据以及对象的地方(即`git-repo/.git/`)
238 | - **工作目录**: 该目录用于存储从git项目数据库中`checkout`出的一个单独的(默认情况下是最新的)项目版本,用于对指定项目版本中的文件进行修改和编辑(即`git-repo/`)
239 | - **暂存区**: 这个区域实际上是存放在git目录(`git-repo/.git/`)中的一个简单的文件,里面存放着下一次需要commit的文件的信息。
240 |
241 | ### 5.3.2 git的安装与配置
242 |
243 | git支持多种操作系统,采用命令行交互界面,在这里,我们以Windows为例来介绍一下如何安装和配置git(MacOS和Ubuntu下的安装则更为简单,使用相应的包管理器即可安装,请读者参考相关帮助信息):
244 |
245 | - 步骤1. 在浏览器中打开git for Windows的下载页面:`https://gitforwindows.org/`
246 |
247 | - 步骤2. 下载安装包,并打开它启动安装向导。在安装过程中,大部分时候只需要采用默认选项,直接点击「Next」即可。只有少数步骤需要留意,其中之一就是在下面这一界面中选择好自己所要安装的组件:
248 |
249 | 
250 |
251 | - 步骤3. 然后是在下面这一界面中设置好环境变量。如果我们希望在Windows自带的`cmd`终端中使用git,在这里就必须选择第二项或第三项:
252 |
253 | 
254 |
255 | - 步骤4. 最后一处是在下面这一界面中配置好文本文件的换行符形式:
256 |
257 | 
258 |
259 | 接下来,我们还要来做一些基本配置。在这里,我用`Python`专门编写了一个git的配置脚本,以便日后重复使用这些配置(具体配置请看代码中的注释说明):
260 |
261 | ```python
262 | #! /usr/bin/env python
263 | '''
264 | @author: lingjie
265 | @name: git_configuration
266 | '''
267 |
268 | import os
269 | import sys
270 | import platform
271 |
272 | title = "= Starting " + sys.argv[0] + "...... ="
273 | n = len(title)
274 | print(n*'=')
275 | print(title)
276 | print(n*'=')
277 |
278 | cmds = [
279 | # 配置用户名
280 | "git config --global user.name 'lingjie'",
281 | # 配置邮箱,请注意,该邮箱纯属虚构,如有雷同必是巧合
282 | "git config --global user.email 'lingjie@mail.com'",
283 | # 配置push命令的默认行为
284 | "git config --global push.default simple",
285 | # 配置git以多种颜色输出信息
286 | "git config --global color.ui true",
287 | # 解决中文文件名乱码问题,前提是终端环境要支持utf8编码
288 | "git config --global core.quotepath false",
289 | # 配置日志信息输出编码为utf8
290 | "git config --global i18n.logOutputEncodiing utf-8",
291 | # 配置提交信息输出编码为utf8
292 | "git config --global i18n.commitEncoding utf-8"
293 | ]
294 |
295 | # 根据所在操作系统设置换行符
296 | if platform.system() == "Windows":
297 | cmds.append("git config --global core.autocrlf true")
298 | else:
299 | cmds.append("git config --global core.autocrlf input")
300 |
301 | for cmd in cmds:
302 | print(cmd)
303 | os.system(cmd)
304 |
305 | print(n*'=')
306 | print("= Done!" + (n-len("= Done!")-1)*' ' + "=")
307 | print(n*'=')
308 | ```
309 |
310 | 当然,如果没有`Python`执行环境,我们也可以手动在终端中执行上述代码存储在`cmds`数组中的配置命令,除了不可重用外,其他效果都是一样的。
311 |
312 | ### 5.3.3 git的基本操作
313 |
314 | 在完成了git的安装和配置之后,我们就可以用git来管理和维护我们的论文项目了。首先,我们需要将论文项目纳入版本控制系统,用git的术语来说,就是将其初始化成一个git仓库。好了,现在让我们进入到论文项目所在的目录,然后执行`git init`命令:
315 |
316 | 
317 |
318 | 在执行完`git init`命令之后,项目目录下就多出了一个叫做`.git`的隐藏子目录。这就是我们之前所说的git目录,该项目后续提交的所有版本都会被存放在其中。接下来,让我们执行`git status`命令来查看一下这个git仓库的状态。在使用git的过程中,我们将会反复使用到这个命 令:
319 |
320 | 
321 |
322 | 我们可以看到,`git status`命令输出了相当详细的信息。其中,第一行表明的是当前所在的版本分支(默认情况下自然是`master`分支)。接下来,它告诉我们目前没有任何需要提交的内容。然后当前项目中有哪些文件可以被纳入到仓库中。正如之前所说,我们将所有的Markdown文件都存放在了`src`目录中,下面让我们根据提示,用`git add`命令将这些文件纳入到版本系统中来,然后再次查看仓库状态:
323 |
324 | 
325 |
326 | *请注意*,我们在这里所添加的文件只是被git标记成了“要提交的变更”,也就是说,它们都处于“暂存”状态。接下来,我们可以根据自己的需要来选择是使用`git commit`命令提交这些文件,还是使用`git rm –cached`命令撤销一些文件的“暂存”状态。在这里,我们来将之前完成的论文初稿提交为项目的第一个版本:
327 |
328 | 
329 |
330 | 由于git生成的版本文件名都是一些用Hash算法生成的字符串,所以我们在使用`git commit`进行版本提交时常常会用`-m`参数来注释一下这次提交的内容,比如我们这次提交的是论文的第一稿,我就将其注释为“初稿”。这样做的目的是为日后的查找和维护提供方便。
331 |
332 | 在完成提交之后,当我们再次执行`git status`时就会看到,当前项目下没有被纳入版本控制的就只有`temp.txt`这个临时文件了,我们也没有打算将其纳入项目。接下来,我们来对论文的第1章做一些模拟修改,改变一下前两段的某些措辞,然后再次执`git status`命令。然后我们从输出信息中可以看到,`src/01_系统概述.md`已经被修改过了:
333 |
334 | 
335 |
336 | 并且,我们可以通过`git diff`命令来查看自己所做的修改:
337 |
338 | 
339 |
340 | 这个时候,如果我们后悔了,可以使用`git checkout -- src/01_系统概述.md`命令来撤销自己在当前工作区中对第1章所做的修改。但如果你已经使用`git add`命令将修改加入到了暂存区中,那就得使用`git reset HEAD src/01_系统概述.md`命令来撤销修改了:
341 |
342 | 
343 |
344 | 但这里,我们会选择将修改内容提交为第二个版本,并注释为“第二稿:第1章的部分措辞变更”。这样一来,这个论文项目就有了两个版本。我们可以使用`git log`命令来查看版本历史:
345 |
346 | 
347 |
348 | 如你所见,git详细记录了我们提交的每一个版本的具体信息(包括checksum值、提交者信息、提交时间),我们可以使用`git checkout`命令将文件恢复到之前的任意一个版本上,操作方式和之前撤销工作目录中的修改是一样的,那次操作实际上就是拿最近版本中的同名文件覆盖掉当前被修改的文件。
349 |
350 | 下面,我们再来简单介绍一下版本控制中的另一种管理操作:分支管理。git的分支管理是异常的简单和方便,可以使用`git branch`命令进行非常直观的操作。首先可以在工作目录下查看当前的项目存在多少分支:
351 |
352 | ```bash
353 | $ git branch
354 | * master
355 | ```
356 |
357 | 如你所见,目前项目中只有一个叫做`master`的主分支,星号(`*`)代表的是我们当前所在的分支。下面,让我们使用`git branch lingjie`命令来为项目添加一个名为`lingjie`的分支,并使用`git checkout lingjie`命令切换到这个新的分支上:
358 |
359 | ```bash
360 | $ git branch lingjie
361 | $ git checkout lingjie
362 | $ git branch
363 | * lingjie
364 | master
365 | ```
366 |
367 | 现在,我们可以看到自己已经位于新建的`lingjie`分支上了。在版本控制系统中,分支的作用是隔离暂时无法确定的修改,使这些修改在不影响主分支的情况下进行,以确定这些修改的可行性。也就是说,从我们建立`lingjie`分支的那一刻起,我们在该分支上所做的所有修改都将独立于`master`分支而存在。如果我们确认了这些修改的可行性,就只需在`master`分支上执行`git merge lingjie`命令将这些修改合并到主分支上即可。当然,如果我们在建立`lingjie`分支之后,在两个分支上都对同一个文件做了修改,并提交了它们,那在执行合并命令时,git会要求你就该文件上的修改做一些版本冲突的处理。例如,我们在两个分支上都创建一个`link.txt`,在`master`分支上该文件内容为“baidu.com”,在`lingje`分支上其内容则为“Google.com”。然后,我们在`master`分支上执行`git merge lingjie`命令就会看到:
368 |
369 | 
370 |
371 | 这时候,我们就要对`link.txt`文件中的内容进行修改,去除掉里面标识冲突的字符,合并才能成功:
372 |
373 | 
374 |
375 | 在合并完成之后,如果我们要删除该分支,可以使用`git branch -d lingjie`命令:
376 |
377 | ```bash
378 | $ git branch -d lingjie
379 | 已删除分支 lingjie (曾为 63c0da1).
380 | $ git branch
381 | * master
382 | ```
383 |
384 | 这时候,我们就会看到`lingjie`分支已经不见了。
385 |
386 | ### 5.3.4 远程仓库操作
387 |
388 | 要参与任何一个git项目的网络协作,必须要了解该如何管理远程仓库。远程仓库是指托管在网络上的项目仓库。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。管理远程仓库的工作,包括添加远程库、移除废弃的远程库、管理各式远程库分支、定义是否跟踪这些分支,等等。在本节,我们就以目前世界上最大的git源码托管服务github为例,来简单介绍一下这些操作。
389 |
390 | 在使用Github远程仓库之前,我们需要先就其ssh链接方式来做一些设置:
391 |
392 | - **步骤1. 首先来配置SSH的密钥**:我们可以先查看系统的用户目录(在windows下通常是`C:\Documents and Settings\`,其他系统通常都是`/home/`),如果当前系统中已经完成了对SSH的配置,用户目录下就会存在一个名为`.ssh`的隐藏目录,该目录下会存有`id_rsa`、`id_rsa.pub`这两个文件。现在请将其备份一下,然后生成新的,在用户目录中打开终端输入以下命令(请注意,请将用尖括号标注的信息替换成你要配置的具体参数):
393 |
394 | ```bash
395 | $ ssh-keygen -t rsa -C “lingjie@mail.com” <此处应输入你自己的电子邮件地址>
396 | Enter file in which to save the key (~/.ssh/id_rsa):
397 | Enter passphrase (empty for no passphrase): <在此处输入你为其设定的密码>
398 | Enter same passphrase again: <重复一遍你设定的密码>
399 | Your identification has been saved in ~/.ssh/id_rsa.
400 | Your public key has been saved in ~/.ssh/id_rsa.pub.
401 | The key fingerprint is:
402 | e8:ae:60:8f:38:c2:98:1d:6d:84:60:8c:9e:dd:47:81 lingjie@mail.com
403 | ```
404 |
405 | - **步骤2. 将生成的公钥知会给我们的github账户**:请打开你的Github账户设置页面,然后找到并点开"SSH and GPG Key"选项页面,点击”New SSH key”按钮, 将你的公钥(id_rsa.pub)字符串复制到其中即可。
406 |
407 | 
408 |
409 | - **步骤3. 测试配置是否成功**:请在终端中输入:
410 |
411 | ```bash
412 | ssh -T git@github.com
413 | ```
414 |
415 | 如果终端输出类似下面这样的信息,即表示我们的设置成功,可以执行后续操作了。
416 |
417 | ```bash
418 | Hi lingjie You’ve successfully authenticated, but GitHub does not provide shell access.
419 | ```
420 |
421 | 接下来,我们就来为当前的论文项目创建一个Github远程仓库,其具体步骤如下:
422 |
423 | - 步骤1. 在登录到github.com之后,我们单击首页中的`New`按钮,打开远程仓库的创建页面。
424 |
425 | - 步骤2. 填入相关信息之后,点击”Create Repository“按钮。
426 |
427 | 
428 |
429 | - 步骤3. 打开终端,进入项目目录,使用`git remote add`命令将一个名为`origin`的远程仓库添加到项目中,然后执行`git remote show`命令查看当前项目的远程仓库,并进一步使用`git remote show origin`命令查看新增仓库的具体信息:
430 |
431 | 
432 |
433 | 在这里,`origin`为git默认远程仓库约定俗成的名称,在执行某些远程仓库操作(譬如`git pull`)时,这个名称是可以省略不写的。除此之外,同一个项目也可以拥有多个远程仓库,我们也可以使用`git remote -v`命令列出这些远程仓库更详细的信息(注:`-v`选项为`-–verbose`的简写,取首字母),譬如下面是本书自身项目拥有的两个远程仓库。除此之外,我们还可以通过`git remote show <远程仓库名>`这个命令格式来查看某个远程仓库的详细信息:
434 |
435 | 
436 |
437 | 接下来,我们需要将论文项目的数据推送(push)到远程仓库上了。项目进行到一个阶段,我们既需要将项目备份在可靠的地方,也有让别人加入项目,进行审阅的网络协作需求。实现这个任务的命令很简单,基本格式为`git push <远程仓库名> <分支名>`。譬如,如果我们想要将当前项目的`master`分支推送到`origin`远程仓库中,可以运行下面的命令:
438 |
439 | 
440 |
441 | 同理,如果我们想要将远程仓库中的数据取回,并将其合并到当前项目的`master`分支中,就只需要执行`git pull origin master`命令即可,这里就不再演示了。无论如何,我们在这里只是针对管理Markdown项目的需要,对git做了一点最基本的介绍。但git是一个非常强大的工具,如果你需要更好地使用这项工具,应该找一本git的专著来学习一番。[^1]
442 |
443 | ## 本章小结
444 |
445 | 在本章,我们围绕着如何”像维护程序项目一样维护Markdown项目“的议题展开了一系列的讨论。首先,我们介绍了一款可以让人们更专注于文字内容审阅和修改的Markdown编辑器:Typora。这款编辑器所见即所得的特性,以及对Markdown扩展语法的强大支持会给我们的自我审阅,以及可直接使用Markdown文档来进行审阅的人们带来极大的便利。接下来,考虑到Markdown的应用不够普及的现实问题,为了让更多的人参与我们作品的审阅,我们为大家介绍了一款专用于转换标记语言格式的工具:Pandoc。通过这个格式转换器,我们可以非常轻松地将Markdown文档转换成人们普遍习惯的`PDF`和Microsoft Word文档。最后,为了从时间维度上对项目的修改进行管理,我们也对如何用git版本控制系统对Markdown项目进行管理和维护,做了一个基本介绍。
446 |
447 | 在下一章中,我们将会介绍几个Markdown在特定领域中的应用,让读者进一步体验Markdown的开放、便捷与强大。我真心地期待有一天,Markdown能成为像儿时的铅笔和橡皮一样文案工具,简单即强大。
448 |
449 |
450 |
451 | [^1]:注释:趁机打个广告,笔者曾经参与翻译过一本《git学习指南》,已由人民邮电出版社出版,如有需要可找来一读。
452 |
--------------------------------------------------------------------------------
/src/06_第六章.md:
--------------------------------------------------------------------------------
1 | # 第6章 Markdown的其他应用
2 |
3 | ## 本章提要
4 |
5 | 到目前为止,我们都是以论文写作这一工作的需求为导引来介绍Markdown在文字创作类项目中的应用的。这样做的好处是能较为全面地涵盖这门标记语言的各种特性和扩展,但对于其开放性,灵活度的体现尚略显不足。Markdown的作用远不止是充当文字创作类项目的“源码”那么单一,它还能用来制作演示文稿、线上电子书和个人博客系统。在这一章中,我们将致力于介绍Markdown在这些特定领域中的应用。
6 |
7 | ## 6.1 制作演示文稿
8 |
9 | 对于平常靠键盘就能完成大部分工作的人来说(譬如我),用Microsoft PowerPoint或Apple Keynote这类软件来制作演示文稿始终是一个挺折磨人的事情。想想那个过程吧,我们必须要时不时让手离开键盘,拿着鼠标来回又点击又拖拽的,短短十几页的演示文稿往往要花费两三个小时以上的时间。而且整个过程充满了“感觉可以了”,“看起来还行”之类的不确定感,也许对于喜欢画画的朋友来说,这是个很熟悉,甚至是很享受的体验,但对我这种喜欢用命令行和少量快捷键来控制计算机,且从不打游戏的人来说,这无疑是一件很难受的事情。当然,使用这些软件的确能制作出包含精美图文的、具有各种炫酷效果的演示文稿,但在大多数情况下,演示文稿的作用只不过是在论文答辩、会议简报或主题演讲的过程中做一点穿针引线,提示重点的辅助而已,如何提炼内容的重点才是我们制作这些演示文稿的关键,那些精美的图案和炫酷的效果对大多数人来说,并没有那么必要。而且习惯了盗版软件的我们可能还忘了,这些软件都不是免费的,价格还并不便宜,鉴于现在的时空背景,我们确定自己能一直使用盗版么?即使愿意花钱,我们也一定能买到这些外国软件吗?这些都恐怕已经不只是道德问题,而是大家可能很快就要面对的现实问题了。[^1]
10 |
11 | ### 6.1.1 Marp简介
12 |
13 | 接下来,就让我们抛开对于炫酷效果的执念,看看Markdown这种自由开放、简洁高效的写作方式能给大家带来的解决方案,也就是我们打算在这里给大家推荐的一款工具:Marp。这是一款基于`Electron`框架[^2]开发的开源软件,它可以将Markdown格式的文字以演示文稿的形式显示出来,并支持导出为`PDF`文档,非常适合于对演示文稿的设计感要求不高,但对其内容产出效率有比较高要求的用户。该软件主要具有以下优点:
14 |
15 | - 开源、自由、免费,使用不受任何非技术因素的限制。
16 | - 跨平台,支持Windows、MacOS、Linux等主流操作系统平台。
17 | - 支持实时预览,提供有Markdown、`1:1 Slide`、`Slide List`三种预览模式。
18 | - 提供有`Default`和`Gaia`两种主题。
19 | - 可以在演示文稿中显示表格、表情符号、数学公式以及背景图这些特定元素。
20 | - 可调整演示文稿的页面尺寸。
21 |
22 | 当然,这款软件也有不足之处 譬如:
23 |
24 | - 软件功能相对单薄,不支持图文绕排等复杂内容的显示。
25 | - `1:1 Slide`预览模式不支持使用上下键翻页。
26 | - Markdown、`Slide List`这两种预览模式则不支持左右滑动。
27 |
28 | 所以,我们在选择一个工具之前需要充分了解自己需求,区分出哪些是必需的,哪些是可有可无的,哪些完全没有必要的,这样才能找出最适合自己的、高性价比的解决方案,切忌意识形态用事,选择华而不实或者不足以解决问题的工具。
29 |
30 | ### 6.1.2 Marp的安装
31 |
32 | Marp是以一个“开箱即用”的软件,安装过程非常简单,步骤如下:
33 |
34 | - 步骤1. 打开浏览器,访问Marp的官方网站:`https://yhatt.github.io/marp/`。
35 |
36 | 
37 |
38 | - 步骤2. 从上面点开的下拉菜单中选择符合自身需求的操作系统平台(譬如,我这里所使用的是Linux 32bit),以下载相应的软件包。
39 |
40 | - 步骤3. 将下载到的软件包解压到我们要安装该软件的目录中,譬如我这里选择的是`/home/owlman/bin/app/marp/`这个目录。
41 |
42 | 
43 |
44 | - 步骤4(可选). 我们也可以为该程序设置一个快捷方式,譬如在Ubuntu下,我们可以创建一个`Marp.desktop`,内容如下:
45 |
46 | ```bash
47 | [Desktop Entry]
48 | Name=Marp
49 | Type=Application
50 | StartupNotify=true
51 | Icon=/home/owlman/bin/app/marp/marp.png
52 | Exec=/home/owlman/bin/app/marp/Marp
53 | ```
54 |
55 | 然后将该文件保存在`/usr/share/applications`目录中即可,当然,在这里我们需要自己准备一个`marp.png`图形文件,以充当快捷方式的图标。
56 |
57 | ### 6.1.3 Marp的使用
58 |
59 | 在完成安装之后,我们就可以通过上述步骤4中创建的快捷方式或者直接在安装目录中单击`Marp`程序文件来启动该程序了,该程序的初始界面如下:
60 |
61 | 
62 |
63 | 现在,让我们先来熟悉一下这个界面。正如你所看到的,Marp的界面采用了常见的菜单栏、编辑区和底部工具栏三段式布局。其编辑区与大多数Markdown编辑器一样分成了左右两个区域,左边是Markdown编码区,右边是预览区。而在底部工具栏的右侧,我们看到三个按钮,它们对应了Marp的三种预览模式,从左至右分别为:
64 |
65 | - Markdown模式:Markdown渲的普通染效果预览。
66 | - `1:1 Slide`模式:演示文稿效果的预览,这也是Marp的默认模式。
67 | - `Slide List`模式:这种形式会以列表的形式预览演示文稿,可执行滑动操作。
68 |
69 | 在熟悉了软件界面之后,接下来就可以开始学习如何用Markdown来制作演示文稿了。但正式这趟学习旅程之前,我们还是有必要先来介绍一下Marp所特有的两个概念:
70 |
71 | - 第一,由于Marp本身就是由Github团队开发的,所以它的Markdown语法采用的是`GitHub Flavored Markdown`风格,支持Github对标准语法所做的部分扩展。
72 |
73 | - 第二,Marp在`GitHub Flavored Markdown`语法的基础上还增加了一种**指令**元素,以便用来调整演示文稿的显示效果。该类元素的格式为``,譬如,如果我们想让演示文稿的页面采用`16:9`的长宽比。就可以在文稿的开头添加``这样一条指令。当然,同一个指令元素中也可以包含多条指令,譬如:
74 |
75 | ```Markdown
76 |
80 | ```
81 |
82 | 这条指令不仅把演示文稿的长宽比设置成了16:9,而且会显示页码。
83 |
84 | 下面,我们通过Marp自带的示例来讲解一下如何用Markdown制作演示文稿。首先,请在Marp的菜单栏中依次点击「Help - Open Example - marp basic example」菜单来打开这个演示文稿示例,下面是该示例在默认的`1:1 Slide`模式下的效果:
85 |
86 | 
87 |
88 | 各位可以自行通过右下角的按钮来查看一下其他预览模式。下面,我们来看一下这个示例前两页的Markdown编码:
89 |
90 | ```Markdown
91 | Marp
92 | ===
93 |
94 | # 
95 |
96 | ##### Markdown presentation writer, powered by [Electron](http://electron.atom.io/)
97 |
98 | ###### Created by Yuki Hattori ( [@yhatt](https://github.com/yhatt) )
99 |
100 | ---
101 |
102 | # Features
103 |
104 | - **Slides are written in Markdown.**
105 | - Cross-platform. Supports Windows, Mac, and Linux
106 | - Live Preview with 3 modes
107 | - Slide themes (`default`, `gaia`) and custom background images
108 | - Supports emoji :heart:
109 | - Render maths in your slides
110 | - Export your slides to PDF
111 |
112 | ---
113 | ```
114 |
115 | 从这两页的编码中,我们可以看出,Markdown的大部分语义元素在Marp中的渲染效果都与普通的Markdown文档一致,唯一不同的是`---`分隔符。该元素在一般Markdown文档中只是一条简单的分割线,而在Marp中,它就成为了演示文稿的分页符,用于将演示文稿的内容切分到不同的页面中,这是我们要学习的第一个Marp特有的Markdown语法。
116 |
117 | 如果我们继续看下去,就会发现这个示例不仅仅是一个语法示范,它本身就是一个Marp环境下的Markdown语法教程。譬如,在该实例第5-11页的编码中,我们可以看到,它详细列举了在Marp的指令元素中可以使用的指令。当然,如果你看不明白或者不喜欢看这些英文的演示文稿也没关系,我们接下来会根据这几页文稿的内容再来做一点转述说明。首先是作用于整个演示文稿的**全局性指令**:
118 |
119 | - **`$theme`指令**:用于指定演示文稿的主题样式,Marp只提供有以下两种主题:
120 |
121 | | 主题名称 | 设置指令 |
122 | | ----------- | -------------------------- |
123 | | **Default** | `` |
124 | | **Gaia** | `` |
125 |
126 | - **`$width` / `$height`指令**:用于指定演示文稿页面的宽度和高度,默认计量单位为像素`px`,除此之外,我们还能指定其他计量单位,包括`cm`、`mm`、`in`、`pt`、`pc`。譬如,我们想将页面宽度设置为9厘米,就可以使用如下指令:
127 |
128 | ```Markdown
129 |
130 | ```
131 |
132 | - **`$size`指令**:用于指定演示文稿页面的长宽比,默认为`4:3`,除此之外,我们可以选择`16:9`、`A0`-`A8`、`B0`-`B8`等预置的长宽比。譬如,如果我们想要将页面设置为`A4`的长宽比,就可以使用如下指令:
133 |
134 | ```Markdown
135 |
136 | ```
137 |
138 | 接下来是只作用于指令所在页面及其后续页面的**页面级指令**(当然,如果将指令置于整个演示文稿的顶部,它一样会影响所有页面):
139 |
140 | - **`page_number`指令**:用于显示页面编号,如果我们想让某页面及其后续页面在右下角显示页面编号,就可以使用如下指令:
141 |
142 | ```Markdown
143 |
144 | ```
145 |
146 | - **`template`指令**:用于指定页面所用的主题模版。譬如,如果我们想使用`gaia`主题的`invert`模版,就可以使用如下指令:
147 |
148 | ```Markdown
149 |
153 | ```
154 |
155 | - **`footer`指令**:用于为当前页面及其后续页面设置页脚。譬如,如果我们想让页面在页脚处显示“这里是页脚”这几个字,就可以使用如下指令:
156 |
157 | ```Markdown
158 |
159 | ```
160 |
161 | - **`prerender`指令**:用于为页面的渲染效果做一些预处理工作。如果我们为页面设置的背景图片过大,我们就可以使用如下指令来改善渲染效果:
162 |
163 | ```Markdown
164 |
165 | ```
166 |
167 | 在上面介绍的最后一个指令时,我们提到了演示文稿页面的背景图片。这也是一个Marp所特有的Markdown语义元素,请参考Marp自带示例的第12页的编码:
168 |
169 | #### Slide background Images
170 |
171 | You can set an image as a slide background.
172 |
173 | ```html
174 | 
175 | ```
176 |
177 | Options can be provided after `bg`, for example ``.
178 |
179 | Options include:
180 |
181 | - `original` to include the image without any effects
182 | - `x%` to include the image at `x` percent of the slide size
183 |
184 | Include multiple`` tags to stack background images horizontally.
185 |
186 | 
187 |
188 | ---
189 |
190 | 正如这张演示文稿中所说明的,在Marp中加入背景图片的语法是``,即在使用图片元素时,在图片说明处将其注明为`bg`。上述页面的渲染效果如下:
191 |
192 | 
193 |
194 | 到目前为止,我们已经将在Marp中制作演示文稿会用到的Markdown语法介绍完了。最后,让我们来综合运用一下这些语法,制作一个用于自我介绍的演示文稿。首先,我们希望这个演示文稿可以转换成`PDF`文档,以便附在论文的前面,所以将页面设置为`A4`。然后,所有页面采用`gaia`主题,并且在页脚处显示"个人简介"的字样,并显示页码。在内容安排上,第一页中会放置一些个人的基本信息,第二页罗列一些代表作品,第三页给出一些联系方式。具体编码如下:
195 |
196 | ```Markdown
197 |
203 |
204 | # 个人简介
205 |
206 | **凌杰**:浙江大学远程教育学院“荣誉学员”、2012年度“十大远程骄子”。目前为自由开发者、技术译者。精通多门编程语言,拥有丰富的软件开发及测试经验。个人崇尚黑客文化,支持开源运动,时常出没于国内外各种技术社区,曾担任上海交通大学饮水思源BBS的技术区区长,并兼任该区C/C++板板主多年。近些年来还参与了多项技术相关的外文翻译工作。
207 |
208 | ---
209 |
210 | ## 代表作品
211 |
212 | - 《元素模式》
213 | - 《git学习指南》
214 | - 《NLTK基础教程》
215 | - 《Python算法教程》
216 | - 《JavaScript面向对象编程指南》
217 |
218 | ---
219 |
220 | ## 联系方式
221 |
222 | - 个人主页:http://owlman.org/
223 | - 新浪微博:https://weibo.com/owlman
224 | - 电子邮件:jie_owlman@163.com
225 | ```
226 |
227 | 下面来看看具体效果,首先是第一页:
228 |
229 | 
230 |
231 | 接着是第二页,我罗列了自己的一些译作:
232 |
233 | 
234 |
235 | 最后一页是是提供本人的联系方式:
236 |
237 | 
238 |
239 | ## 6.2 发布为线上电子书
240 |
241 | 古往今来,对于许多喜欢写作的人来说,出版个人文集一直是人生的一大愿望。这在以前可真不是一件容易的事,不仅累积的文章数量要能足以汇集成册,而且这些文章的主题、内容要能被市场接受,具有一定的市场价值,这样才会有出版社或书商愿意出版,当然,你有足够的声望或资金也可以说服出版社出版自己的个人文集。总而言之,写出大量符合市场需求的文章,和成为名人或富人都不是轻而易举就可以做到的。但在如今这个互联网时代,如果我们的目的不是想靠文集赚取版税,只是想把自己的文章分享给大众的话,其实是不用劳烦出版社和那些书商的,我们可以通过制作**线上电子书**或者构建**个人博客系统**的方式来发布自己的文集。关于博客系统的构建,我们会在下一节中介绍,这里先来介绍线上电子书的制作。
242 |
243 | 需要注意的是,线上电子书与我们在Kindle等设备或专用软件中使用的文件型电子书不一样,它本质上是一个静态网站,而不是一个具有特定格式,需要权威机构授权的电子文件。这意味着,制作线上电子书的成本实际上与构建静态网站是一样的,基本上只需要购置一个域名和一个能请提供`HTTP`服务的服务器即可。而我们之前也提过,Markdown这门标记语言的设计初衷就为了方便将人们撰写的文章转换成相应的`HTML`页面,所以它在制作线上电子书方面具有先天的优势。
244 |
245 | 在这里,我们打算为大家介绍一个基于Markdown来制作线上电子书的工具:gitbook。千万不要被名字迷惑了,就像`JavaScript`不是基于`Java`的脚本一样,gitbook也不是一本关于git的书,它是一个基于Node.js运行环境的、用于制作和管理电子书的命令行工具。该工具能将Markdown或`AscilDoc`格式的文档编译成静态网站或`PDF`、`ePub`等格式的电子书,并结合git版本控制系统来管理这些电子书及其源文件,是目前最流行的开源书籍解决方案。
246 |
247 | ### 6.2.1 gitbook的安装
248 |
249 | 要想安装gitbook,我们首先得要确认自己的计算机上安装了Node.js运行环境[^3],具体方法就是在命令行终端中输入`node -v`命令,只要看到终端返回如下版本信息,就说明当前环境中已经安装了Node.js运行环境:
250 |
251 | 
252 |
253 | 如果没有看到类似的版本信息,那就说明你需要先自己安装一下Node.js运行环境,然后才能继续接下来的学习。我们在*附录B:了解一下Node.js*中介绍了如何在Windows和Ubuntu上安装Node.js的相关内容,读者可自行参考。在确认了Node.js运行环境之后,我们就可以通过Node.js的包管理器npm来安装gitbook了,具体命令如下:
254 |
255 | ```bash
256 | npm install -g gitbook-cli
257 | ```
258 |
259 | 如果安装过程一切顺利(如果是MacOS或Linux系统,安装时可能还会遇到用户权限的问题,请切换至root用户或用`sudo`命令来提升权限),我们在命令行终端中输入`gitbook -V`就能看到如下版本信息了:
260 |
261 | 
262 |
263 | 至此,gitbook就算是安装好了。接下来,让我们继续以之前的毕业论文为例,看看如何用gitbook将其发布为线上电子书。
264 |
265 | ### 6.2.2 gitbook的基本使用
266 |
267 | 要将之前的论文项目发布成一部线上电子书,首先需要将其初始化一个gitbook项目。下面,让我们打开命令行终端,进入到论文项目的所在目录中,并执行`gitbook init`命令:
268 |
269 | 
270 |
271 | 在上述初始化过程顺利完成之后,我们就可以看到论文的项目目录下多了两个文件,这两个文件各自都有着特定的功能:
272 |
273 | - **README.md**:这是项目的自述文件,默认情况下,该文件也会是该线上电子书的首页,我们可以将其当作封面来处理。
274 | - **SUMMARY.md**:这是项目的目录文件,线上书籍的目录安排,章节顺序要在该文件中设置。
275 |
276 | 下面,我们就来具体设置一下这两个文件。首先是`README.md`文件,我们打算让它成为这本书的封面,所以在其中使用了一些分割线、空行和列表等语义元素来呈现这篇论文的标题和署名,具体如下:
277 |
278 | ```Markdown
279 | ------
280 |
281 |
282 |
283 | **浙江大学远程教育学院 — 本科生毕业论文**
284 |
285 | # 网上书籍销售系统的设计
286 |
287 |
288 |
289 | - 姓名:凌杰
290 | - 导师:王某某 教授
291 | - 专业:计算机科学与技术
292 | - 学号:D0000000000001[^1]
293 | - 日期:2006年5月31日
294 |
295 |
296 |
297 |
298 |
299 | ------
300 |
301 | [^1]:本学号纯属虚构,如有雷同概不负责。
302 | ```
303 |
304 | 设计完了封面,我们再来编辑`SUMMARY.md`文件,设置一下这本书的目录和章节顺序,具体内容如下:
305 |
306 | ```Markdown
307 | ## 目录
308 |
309 | - [论文封面](README.md)
310 | - [第1章:系统概述](src/01_系统概述.md)
311 | - [第2章:系统数据库的设计](src/02_系统数据库的设计.md)
312 | - [第3章:功能模块的划分](src/03_功能模块的划分.md)
313 | - [第4章:开发环境与工具的选择](src/04_开发环境与工具的选择.md)
314 | - [第5章:各功能模块的实现](src/05_各功能模块的实现.md)
315 | - [第6章:系统程序的发布](src/06_系统程序的发布.md)
316 | - [第7章:设计总结](src/07_设计总结.md)
317 |
318 | ```
319 |
320 | 如你所见,目录的设置就是将各章节的源文件以链接的形式表列`SUMMARY.md`文件中。在保存该文件之后,我们接下来就可以用`git build .`命令来生成组成线上电子书的`HTML`页面了:
321 |
322 | 
323 |
324 | 如果一切顺利,我们就在论文项目的目录下看到一个名为`_book`的子目录,组成线上电子书的`HTML`页面都被存储在了该目录下,我们可以像发布一般静态网站一样将它们发布到服务器上。为了方便电子书制作过程中的测试,gitbook自身也提供了一个Web服务器程序,我们可以使用`gitbook serve`命令来启动该服务器:
325 |
326 | 
327 |
328 | 现在,我们就可以根据上述输出中最后一行给出的`URL`来查看生成的线上电子书了。请打开Web浏览器并于地址栏中输入`http://localhost:4000/`,你就应该会看到如下页面:
329 |
330 | 
331 |
332 | 我们可以通过单击左侧的目录链接跳转到论文的任意一章,以查看效果。譬如下面是第5章的内容:
333 |
334 | 
335 |
336 | ### 6.2.3 gitbook的高级配置
337 |
338 | 到目前为止,我们所生成的只是一个最基本的gitbook线上电子书,所有的参数设置都是默认的。显然,默认配置当中有些东西并不适合我们,譬如,右上角“分享”按钮中的Facebook和Twitter显然对于大多数国内用户来说并没有多大意义。另外,我们还希望论文能支持数学公式和`Mermaid`图库的显示,这需要我们安装一些额外的插件。所以,我们接下来要对上面生成的线上电子书做一些个性化定制。在gitbook中,个性化的设置是通过一个叫做`book.json`配置文件。该文件需要我们自己来创建,并保存在论文项目的根目录中。在这里,先给大家看看我为该论文项目所做的配置:
339 |
340 | ```json
341 | {
342 | "title": "《网上书籍销售系统的设计》",
343 | "description": "一篇用Markdown撰写的毕业论文",
344 | "author": "凌杰",
345 |
346 | "language": "zh-hans",
347 |
348 | "links": {
349 | "sidebar": {
350 | "Owlman的个人网站": "http://owlman.org/"
351 | }
352 | },
353 |
354 | "plugins": [
355 | "github", // 添加github图标链接
356 | "splitter", // 使侧边栏的宽度可被自由调整
357 | "-sharing", // 卸载默认分享插件
358 | "sharing-plus", // 增强型分享插件
359 | "-highlight", // 卸载默认的代码高亮插件
360 | "prism", // 基于Prism的代码高亮
361 | "katex", // 显示数学公式
362 | "mermaid", // 显示Mermaid图库的渲染效果
363 | "theme-comscore", // 一款gitbook主题
364 | "tbfed-pagefooter", // 为页面添加页脚信息
365 | "sitemap" // 生成站点地图
366 | ],
367 |
368 | "pluginsConfig": {
369 | "fontsettings": {
370 | "theme": "white",
371 | "family": "serif",
372 | "size": 12
373 | }, // 设置默认样式和字体
374 |
375 | "tbfed-pagefooter": {
376 | "copyright":"© 凌杰",
377 | "modify_label": "该文件修订时间:",
378 | "modify_format": "YYYY-MM-DD HH:mm:ss"
379 | }, // 设置页脚信息的显示格式
380 |
381 | "sharing": {
382 | "douban": false,
383 | "facebook": false,
384 | "google": false,
385 | "hatenaBookmark": false,
386 | "instapaper": false,
387 | "line": false,
388 | "linkedin": false,
389 | "messenger": false,
390 | "pocket": false,
391 | "qq": false,
392 | "qzone": false,
393 | "stumbleupon": false,
394 | "twitter": false,
395 | "viber": false,
396 | "vk": false,
397 | "weibo": false,
398 | "whatsapp": false,
399 | "all": [
400 | "weibo","qq","qzone","google","douban"
401 | ]
402 | }, // 设置共享插件要显示的选项
403 |
404 | "github": {
405 | "url": "https://github.com/owlman"
406 | }, // 设置github图标的链接
407 |
408 | "theme-default": {
409 | "showLevel": false
410 | }, // 设置主题
411 |
412 | "prism": {
413 | "css": [
414 | "prismjs/themes/prism-tomorrow.css"
415 | ]
416 | }, // 设置代码高亮的样式
417 |
418 | "sitemap" : {
419 | "hostname": "http://owlman.org/"
420 | } // 生成站点地图
421 | }
422 | }
423 | ```
424 |
425 | 下面,让我们来逐一介绍一下这些设置:
426 |
427 | - **基本信息**:`title`、`description`和`author`这三个选项所设定的是线上电子书作为一个网站的基本信息,它们最终会被编译成网页头信息中的各种元数据标签,这些信息有助于被搜索引擎抓取,提高网站被相关关键字搜索到的机率。
428 | - **语言设定**:`language`选项所设定的是这部线上电子书所使用的语言,这里我们设定的是`zh-hans`,即*简体中文*,如果你想使用港澳台地区人民比较熟悉的*繁体中文*,就将其设定为`zh-hant`。
429 | - **链接设定**:`links`选项所设定的是左侧导航区除目录部分意外的链接,譬如我在这里添加了自己的个人网站。
430 | - **安装插件**:`plugins`选项所设定的是要安装的插件,这里需要注意的是,gitbook自身默认就安装了一些插件,如果我们安装的插件在功能上与默认插件有冲突,就需要这些默认插件的名称前面加一个`-`符号,以示卸载。譬如在这里,我们用功能更为全面的`sharing-plus`代替了原来的`sharing`插件。至于这里安装的这些插件,我已经在上面的注释中为它们的功能做了说明。
431 | - **插件配置**:`pluginsConfig`选项所设定的是插件的一些具体配置,我在上面的注释中对这些配置的作用已经做了具体的说明。
432 |
433 | 在设置好配置文件之后,我们就可以在命令行终端中执行`gitbook install .`命令来安装插件,并用`gitbook build .`命令来重新生成电子书了。如果一切顺利,当我们再次通过`gitbook serve`命令来启动测试服务器,并访问`http://localhost:4000/`时,就应该会看到如下页面:
434 |
435 | 
436 |
437 | 当然,gitbook的插件体系是非常庞大的,我们通过访问gitbook的官方插件列表[^4]来为自己寻找更多适合的插件。
438 |
439 | ## 6.3 架设个人博客系统
440 |
441 | 其实,相对于线上电子书这种分享文章的方式,我相信博客可能是一种更为大众所熟悉的文章发布形式。我个人用过不少各种免费的博客服务,包括CSDN、博客园、简书等。这些博客服务也都支持用Markdown语法来编写文章,它们用起来简单而方便,文章也比较容易被大家看到。但选择这些服务的缺点也很明显,那就是我们必须忍受服务方由于各种各样的主客观因素,对文章内容所进行的各式各样,让人无所适从的审查,一不小心就会被通知删文。除此之外,文章的周围还时常会被插入各种不相干的广告,看到我们无偿的分享却成为别人赚钱的工具,有时候也是一件让人反胃的事。
442 |
443 | 当然,我们也可以使用WordPress这样的专业博客框架来构建自己的博客系统,但这类博客框架通常需要服务器支持`PHP`、`JSP`这样的动态页面和MySQL这样的数据库服务,租用服务器的花销并不算小。想想看,我们写文章是无偿分享也就算了,结果每年还要搭出去几百块钱。或许你觉得这点小钱不叫事,但你可能忘记了,动态网站的维护本身也是个很耗费精力的事情,这意味着你还要花大把时间在一个不赚钱的网站上,除非有人想做个专门敲代码的和尚,否则怎么看这都不是一个长久之计。
444 |
445 | 幸运的是,我们还有第三种选择,那就是使用类似于gitbook这样的工具,根据我们写的文章生成静态网站,然后发布到github page这类免费的静态Web服务器上,即使不免费,也比需要数据库和动态页面服务的服务器要便宜不少,少抽一包烟或少买几件游戏装备也就有了。而且,静态网站的维护也比较简单,我们可以放心地把注意力放在自己喜欢的写作上了(当然,请务必要先安抚好老婆和孩子)。
446 |
447 | 下面,我们就来给大家介绍一款与gitbook非常类似,用于生成静态博客网站的工具:Hexo,这也是一款基于Node.js的命令行工具,值得一提的是,由于Hexo的创建者是一位台湾人,因此中文的资源相对来说是比较充裕的,大家可以直接去其官方网站`https://hexo.io/zh-cn/`查看其相关资料,本节接下来的很多内容就来自于这些资料。
448 |
449 | ### 6.3.1 构建博客
450 |
451 | 下面,我们先来架构一个基本的Hexo博客。首先,我们需要安装Hexo的命令行工具。当然,在安装该命令行工具之前,务必要记得先确认自己的计算机中是否已经安装了git和Node.js(尚未安装Node.js的朋友,可以参考*附录B:了解一下Node.js*中的相关内容自行安装该运行环境)。然后,我们就可以使用`npm`包管理器安装Hexo了,具体命令如下:
452 |
453 | ```bash
454 | npm install -g hexo-cli
455 | ```
456 |
457 | 如果安装过程一切顺利(如果是MacOS或Linux系统,安装时可能还会遇到用户权限的问题,请切换至root用户或用`sudo`命令来提升权限),我们在命令行终端中输入`hexo -V`就能看到如下版本信息了:
458 |
459 | 
460 |
461 | 在安装好了hexo命令行工具之后,我们就可以用它来建构一个基本的博客系统了。和之前的线上电子书不同,这回我们打算从零开始构建一个博客。所以,让我们在工作目录中打开命令行终端,执行`hexo init My_blog`命令(在这里,`My_blog`是这个博客项目的名称,它可以是任何一个你喜欢的名称),然后,再进入到新生成的`My_blog`目录中,执行`npm install`命令。到这一步为止,一个基本的博客系统其实就已经构建完成了,我们可以来看看该目录下生成了哪些目录和文件:
462 |
463 | 
464 |
465 | 接下来,让我们逐一为大家介绍一下这些目录和文件:
466 |
467 | - **node_modules目录**: 该目录中存放的是Hexo项目所依赖的Node.js模块包,每个基于Node.js运行环境的项目中通常都会有这个目录,包括之前的gitbook。
468 | - **public目录**:Hexo最终生成的静态网站就存储在此目录中,在发布博客的时候只需要发布该目录中的内容即可。
469 | - **scaffolds目录**:用于存放文章模版的目录。
470 | - **source目录**:用于存放博客文章的目录,我们用Markdown撰写的博客文章就被存储在这里。
471 | - **themes目录**:用于存放博客主题的目录。
472 | - **package.json文件**:用于存储该博客框架的基本信息。
473 | - **_config.yml文件**: 博客的配置文件。
474 |
475 | 现在,让我们将这个基本博客运行起来,看看它的初始状态是怎么样的。请在项目目录中打开命令行终端,执行`hexo generate`命令(或者该命令的简写形式`hexo g`)生成该博客的静态站点。然后再执行`hexo server`命令(或者该命令的简写形式`hexo s`)来启动Hexo自带的测试服务器。如果一切顺利,当我们在Web浏览器中访问`http://localhost:4000/`时,就应该会看到如下页面:
476 |
477 | 
478 |
479 | ### 6.3.2 配置博客
480 |
481 | 我们在上面看到的,只是Hexo框架所建构的一个基本博客,其所有的配置都是默认的。接下来,我们会对该博客做一些个性化的配置,安装一个主题,然后添加几篇我们自己的文章,让它真正成为我们的个人博客。首先,让我们通过Hexo博客框架在默认状态下的配置文件`_config.yml`,了解一下这个博客可以配置那些内容:
482 |
483 | ```yml
484 | # Hexo Configuration
485 | ## Docs: https://hexo.io/docs/configuration.html
486 | ## Source: https://github.com/hexojs/hexo/
487 |
488 | # Site
489 | title: Hexo
490 | subtitle:
491 | description:
492 | keywords:
493 | author: John Doe
494 | language:
495 | timezone:
496 |
497 | # URL
498 | ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
499 | url: http://yoursite.com
500 | root: /
501 | permalink: :year/:month/:day/:title/
502 | permalink_defaults:
503 |
504 | # Directory
505 | source_dir: source
506 | public_dir: public
507 | tag_dir: tags
508 | archive_dir: archives
509 | category_dir: categories
510 | code_dir: downloads/code
511 | i18n_dir: :lang
512 | skip_render:
513 |
514 | # Writing
515 | new_post_name: :title.md # File name of new posts
516 | default_layout: post
517 | titlecase: false # Transform title into titlecase
518 | external_link: true # Open external links in new tab
519 | filename_case: 0
520 | render_drafts: false
521 | post_asset_folder: false
522 | relative_link: false
523 | future: true
524 | highlight:
525 | enable: true
526 | line_number: true
527 | auto_detect: false
528 | tab_replace:
529 |
530 | # Home page setting
531 | # path: Root path for your blogs index page. (default = '')
532 | # per_page: Posts displayed per page. (0 = disable pagination)
533 | # order_by: Posts order. (Order by date descending by default)
534 | index_generator:
535 | path: ''
536 | per_page: 10
537 | order_by: -date
538 |
539 | # Category & Tag
540 | default_category: uncategorized
541 | category_map:
542 | tag_map:
543 |
544 | # Date / Time format
545 | ## Hexo uses Moment.js to parse and display date
546 | ## You can customize the date format as defined in
547 | ## http://momentjs.com/docs/#/displaying/format/
548 | date_format: YYYY-MM-DD
549 | time_format: HH:mm:ss
550 |
551 | # Pagination
552 | ## Set per_page to 0 to disable pagination
553 | per_page: 10
554 | pagination_dir: page
555 |
556 | # Extensions
557 | ## Plugins: https://hexo.io/plugins/
558 | ## Themes: https://hexo.io/themes/
559 | theme: landscape
560 |
561 | # Deployment
562 | ## Docs: https://hexo.io/docs/deployment.html
563 | deploy:
564 | type:
565 |
566 | ```
567 |
568 | 如你所见,该配置文件被分成了若干组参数。下面,让我们来为大家介绍一些常用的参数。首先是与站点SEO工作相关的配置,它们包含了以下参数:
569 |
570 | | 参数 | 描述 |
571 | |-------------|-----------------------------------------------|
572 | | title | 网站的标题。 |
573 | | subtitle | 网站的副标题。 |
574 | | description | 网站的自述性说明。 |
575 | | author | 博客作者的名字。 |
576 | | language | 网站使用的语言。 |
577 | | timezone | 网站所使用的时区。默认值为该系统所在计算机使用的时区。 |
578 |
579 | 这部分参数的值最终会被编译成网页头信息中的各种元数据标签,这些信息有助于被搜索引擎抓取,提高网站被相关关键字搜索到的机率。接下来, 是一些站点URL参数:
580 |
581 | | 参数 | 描述 |
582 | |-------------|-----------------------------------------------|
583 | | url | 网站的域名。 |
584 | | root | 网站的根目录。 |
585 | | permalink | 博客文章的“永久链接”的格式。 |
586 | | permalink_defaults | 永久链接中各部分的默认值。 |
587 |
588 | 在这里,我们需要把`url`设置改成自己的域名,譬如,如果我们的域名是`http://blog.owlman.org`,那么对我们在2019年06月03日创建的某篇博客文档`temp.md`,根据`permalink`的默认格式,它的永久链接就应该是`http://blog.owlman.org/2019/06/03/temp`。当然,你也可以将`permalink`设定为其他格式,下面是官方给出的示例(这里的`hello-world`就是之前博客中出现的那篇默认范文):
589 |
590 | | 参数 | 结果 |
591 | |------------------------------|-----------------------------------------------|
592 | | `:year/:month/:day/:title/` | 2013/07/14/hello-world |
593 | | `:year-:month-:day-:title.html` | 2013-07-14-hello-world.html |
594 | | `:category/:title` | foo/bar/hello-world |
595 |
596 | 再往下,对于`Directory`、`Writing`这些分组的参数,我们大多数时候不需要更改它们,保持默认值就好。在这里,我们来重点关注一下博客主题的设置。通过配置文件中的`theme`参数,我们可以知道Hexo博客的默认主题,也就是我们之前看到的那个主题叫做`landscape`。之前在介绍项目结构的时候,我们曾经提到过,主题文件都被存储在`theme`这个目录下面。所以,如果我们想更换主题,可以去Hexo官网的主题页面`https://hexo.io/themes/`中找一个自己喜欢的主题,将它下载到`theme`目录下,然后将配置文件中的`theme`参数设定为该主题的名字即可。譬如,如果我在这里想安装一款名为`Anisina`的主题,那只需要在项目目录下打开命令行终端,输入如下命令即可:
597 |
598 | 
599 |
600 | 然后,再将`_config.yml`文件中的`theme`参数设置为`Anisina`即可。现在,你是不是迫不及待想看看自己的博客是什么样子了?不要着急。为了让呈现效果更好一点,我们还需在加入一篇自己的文章。在Hexo博客中,新文章可以使用`hexo new <博客标题>`命令来添加,譬如我们想添加一篇书评的话,就可以执行如下命令:
601 |
602 | 
603 |
604 | 如你所见,我将之前写的一篇关于《大教堂与集市》的书评添加到了博客中。现在,我们可以再次将博客运行起来,看看个性化配置的效果了。请注意,在重新生成博客之前,最好先使用`hexo clean`命令清除一下之前生成的结果。具体来说,就是在项目目录下打开命令行终端,依次输入下面三个命令:
605 |
606 | ```bash
607 | hexo clean
608 | hexo generate
609 | hexo sever
610 | ```
611 |
612 | 如果一切顺利,当我们在Web浏览器中访问`http://localhost:4000/`时,就应该会看到自己安装的主题和添加的新文章了:
613 |
614 | 
615 |
616 | 当然,我们也可以看到这个博客的主题还有些需要设置的地方(譬如导航栏,文章标题的配图等)。但这些内容需要我们根据自己所选主题的项目文档来做设置,譬如对于我在这里所选的这款主题,就要去`https://github.com/haojen/hexo-theme-Anisina`这个项目去寻找相关的设置说明,这里就不多做说明了,毕竟每个人会选择的主题都不一样。
617 |
618 | ### 6.3.3 部署博客
619 |
620 | 在配置好博客之后,我们就需要将其部署到Web服务器上。部署Hexo博客有两种方法。第一种是一般静态网站的部署方式,租用好域名和服务器之后,将项目生成的静态网站通过FTP或SSH上传到服务器上,然后做好域名解析的设置即可。这属于网站开发方面的内容了,并不是本书主要讨论的话题,这里就不多做说明了,读者可自行去查阅相关资料。但这种部署方式有个明显的缺点,那就是大部分单独的Web服务器都不是免费的,需要我们每年支付一定的费用。这对于大部分不盈利的博客来说,不是一个长久之计。
621 |
622 | 另一种方式就是使用Github Pages这样的服务,这种服务原本是让开源项目的开发者为自己的项目做一些说明性页面的,但如今也有越来越多的人将其作为静态网站的部署方式来使用,毕竟这是一个完全免费的服务。甚至,gitbook、Hexo这些工具根本就是面向这种部署方式来开发的。下面,我们就来介绍一下如何用Hexo的自动部署工具来部署博客,其具体步骤如下:
623 |
624 | - 步骤1. 在登录到github.com上,创建一个新的代码仓库(具体方法请参考第5章中的说明)。在这里,我将该仓库命名为`Hexo_demo`。
625 |
626 | 
627 |
628 | - 步骤2. 打开博客的配置文件 `_config.yml`,将文件最后名为`deploy`的一组参数修改如下:
629 |
630 | ```bash
631 | deploy:
632 | type: git
633 | repo: git@github.com:owlman/Hexo_demo.git
634 | branch: master
635 | ```
636 |
637 | - 步骤3. 现在我们需要安装一个名为`deploy-git`的插件,这是Hexo的部署命令。请在到项目目录下打开命令行终端,执行如下命令:
638 |
639 | ```bash
640 | npm install hexo-deployer-git --save
641 | ```
642 |
643 | - 步骤4. 然后依次执行下面三个命令,即可完成部署:
644 |
645 | ```bash
646 | hexo clean
647 | hexo generate
648 | hexo deploy
649 | ```
650 |
651 | 如果一切顺利,当我们会到之前创建的Github仓库页面,就会看到生成的网站已经被上传到项目中了:
652 |
653 | 
654 |
655 | - 步骤5. 接下来。我们需要进入到该项目仓库的`Setting`页面中,将其Github Pages部分的`Source`选项设置为`master`分支:
656 |
657 | 
658 |
659 | 如果一切顺利,当我们在Web浏览器中访问上面给出的页面链接`https://owlman.github.io/Hexo_demo/`时,就应该会看到之前配置好的博客。
660 |
661 | 当然,必须指出的是,我们在这里介绍的只是Hexo博客最简单的应用,要想部署一个真正堪用的博客,你还需要参照Hexo的官方文档,以及你所选主题的项目文档,做出更细致的修改,这也需要掌握一定的Web开发技术(譬如,`HTML`、`CSS`、`JavaScript`等),但这些不是本书所要讨论的话题,这里就不多做说明了。
662 |
663 | ## 本章小结
664 |
665 | 在本章,我们为大家介绍了如何用Markdown制作演示文稿、线上电子书以及撰写博客。初步展示了Markdown作为一种写作方式的广泛适用性、在我个人看来,Markdown已经不仅仅是一门用于写作的轻量级标记语言了,它更是一种更新型的写作方式,它将“数据与样式分离”、“数据与界面分离”等程序设计思维引入到了写作领域,使我们可以像写程序一样来撰写文章。随着这种写作方式的普及,软件开源的精神最终也会被引入到写作领域来,这将为喜欢写作的人们带来更自由的创作空间和更学术的创作氛围,我真心期待着这样的未来,这本书就是为此而作的。
666 |
667 |
668 |
669 | [^1]:注释:在作者写下这些文字的同时,新闻正在热炒Google终止向华为提供软件支持的事件。
670 | [^2]:注释:这是一个基于JavaScript、HTML、CSS构建的跨平台的桌面应用框架。官方网站:https://electronjs.org/
671 | [^3]:注释:Node.js是一个能够在服务器端运行JavaScript的开放源代码、跨平台JavaScript运行环境。官方网站:https://nodejs.org/
672 | [^4]:注释:https://plugins.gitbook.com/
673 |
--------------------------------------------------------------------------------
/src/A1_附录A.md:
--------------------------------------------------------------------------------
1 | # 附录A:Makefile简易教程
2 |
3 | ## A.1 Makefile简介
4 |
5 | 在软件开发中,make通常被视为一种软件构建工具。该工具主要经由读取一种名为`makefile`或`Makefile`的文件来实现软件的自动化建构。它会通过一种被人们称之为“目标(target)”概念来检查相关文件之间的依赖关系,这种依赖关系的检查系统非常简单,主要通过对比文件的修改时间来实现。在大多数情况下,我们主要用它来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。
6 |
7 | ### A.1.1 优点与缺点
8 |
9 | 与大多数古老的UNIX工具一样,make也分别有着人数众多的拥护者和反对者。它在适应现代大型软件项目方面有着许许多多的问题。但是,依然有很多人坚定地认为(包括我)它能应付绝大多数常见的情况,而且使用非常的简单,功能强大,表达清楚。无论如何,make如今仍然被用来编译很多完整的操作系统,而且它的那些“更为现代”的替代品们在基本操作上与它没有太大差别。
10 |
11 | 当然,随着现代的集成开发环境(IDE)的诞生,特别是非UNIX的平台上,很多程序员不再手动管理源代码之间的依赖关系,甚至不用去管哪些文件是这个项目的一部分,而是把这些任务交给了他们的开发环境去做。类似的,很多现代的编程语言有自己专属的、能高效配置依赖关系的方法(譬如Ant)。
12 |
13 | ### A.1.2 主要版本
14 |
15 | make程序经历过各方多次的改写与重写,各方都依据自己的需要做了一些特定的改良。目前市面上主要流行有以下几种版本:
16 |
17 | - **GNU make**:GNU make对make的标准功能(通过clean-room工程)进行了重新改写,并加入作者自认为值得加入的新功能,常和GNU编译系统一起被使用,是大多数GNU Linux默认安装的工具。
18 |
19 | - **BSD make**:该版本是从Adam de Boor制作的版本上发展起来的。它在编译目标的时有并发计算的能力。主要应用于FreeBSD,NetBSD和OpenBSD这些系统。
20 |
21 | - **Microsoft nmake**:该版本主要用于微软的Windows系统中,需要注意的是,微软的nmake与UNIX项目中的nmake是两种不同的东西,千万不要混淆。
22 |
23 | ## A.2 从一个简单的例子入手
24 |
25 | 我们可以用K&R C[^1]中4.5那个例子来做个说明。在这个例子中,我们会看到一份主程序代码(`main.c`)、三份函数代码(`getop.c`、`stack.c`、`getch.c`)以及一个头文件(`calc.h`)。通常情况下,我们需要这样编译它:
26 |
27 | ```bash
28 | gcc -o calc main.c getch.c getop.c stack.c
29 | ```
30 |
31 | 如果没有makefile,在开发+调试程序的过程中,我们就需要不断地重复输入上面这条编译命令,要不就是通过终端的历史功能不停地按上下键来寻找最近执行过的命令。这样做两个缺陷:
32 |
33 | 1. 一旦终端历史记录被丢失,我们就不得不从头开始;
34 |
35 | 2. 任何时候只要我们修改了其中一个文件,上述编译命令就会重新编译所有的文件,当文件足够多时这样的编译会非常耗时。
36 |
37 | 那么Makefile又能做什么呢?我们先来看一个最简单的makefile文件:
38 |
39 | ```makefile
40 | calc: main.c getch.c getop.c stack.c
41 | gcc -o calc main.c getch.c getop.c stack.c
42 | ```
43 |
44 | 现在,你看到的就是一个最基本的Makefile语句,它主要分成了三个部分,第一行冒号之前的`calc`,我们称之为目标(target),被认为是这条语句所要处理的对象,具体到这里就是我们所要编译的这个程序`calc`。冒号后面的部分(`main.c`、`getch.c`、`getop.c`、`stack.c`),我们称之为依赖关系表,也就是编译`calc`所需要的文件,这些文件只要有一个发生了变化,就会触发该语句的第三部分,我们称其为命令部分,相信你也看得出这就是一条编译命令。现在我们只要将上面这两行语句写入一个名为`Makefile`或`makefile`的文件,然后在终端中输入`make`命令,就会看到它按照我们的设定去编译程序了。
45 |
46 | > 请注意,在第二行的`gcc`命令之前必须要有一个tab缩进。语法规定Makefile中的任何命令之前都必须要有一个tab缩进,否则make就会报错。
47 |
48 | 接下来,让我们来解决一下效率方面的问题,先初步修改一下上面的代码:
49 |
50 | ```makefile
51 | cc = gcc
52 | prom = calc
53 | src = main.c getch.c getop.c stack.c
54 |
55 | $(prom): $(src)
56 | $(cc) -o $(prom) $(src)
57 | ```
58 |
59 | 如你所见,我们在上述代码中定义了三个常量`cc`、`prom`以及`src`。它们分别告诉了make我们要使用的编译器、要编译的目标以及源文件。这样一来,今后我们要修改这三者中的任何一项,只需要修改常量的定义即可,而不用再去管后面的代码部分了。
60 |
61 | > 请注意,很多教程将这里的`cc`、`prom`和`src`称之为变量,个人认为这是不妥当的,因为它们在整个文件的执行过程中并不是可更改的,作用也仅仅是字符串替换而已,非常类似于C语言中的宏定义。或者说,事实上它就是一个宏。
62 |
63 | 但我们现在依然还是没能解决当我们只修改一个文件时就要全部重新编译的问题。而且如果我们修改的是`calc.h`文件,make就无法察觉到变化了(所以有必要为头文件专门设置一个常量,并将其加入到依赖关系表中)。下面,我们来想一想如何解决这个问题。考虑到在标准的编译过程中,源文件往往是先被编译成目标文件,然后再由目标文件连接成可执行文件的。我们可以利用这一点来调整一下这些文件之间的依赖关系:
64 |
65 | ```makefile
66 | cc = gcc
67 | prom = calc
68 | deps = calc.h
69 | obj = main.o getch.o getop.o stack.o
70 |
71 | $(prom): $(obj)
72 | $(cc) -o $(prom) $(obj)
73 |
74 | main.o: main.c $(deps)
75 | $(cc) -c main.c
76 |
77 | getch.o: getch.c $(deps)
78 | $(cc) -c getch.c
79 |
80 | getop.o: getop.c $(deps)
81 | $(cc) -c getop.c
82 |
83 | stack.o: stack.c $(deps)
84 | $(cc) -c stack.c
85 | ```
86 |
87 | 这样一来,上面的问题显然是解决了,但同时我们又让代码变得非常啰嗦,啰嗦往往伴随着低效率,是不祥之兆。经过再度观察,我们发现所有`.c`都会被编译成相同名称的`.o`文件。我们可以根据该特点再对其做进一步地简化:
88 |
89 | ```makefile
90 | cc = gcc
91 | prom = calc
92 | deps = calc.h
93 | obj = main.o getch.o getop.o stack.o
94 |
95 | $(prom): $(obj)
96 | $(cc) -o $(prom) $(obj)
97 |
98 | %.o: %.c $(deps)
99 | $(cc) -c $< -o $@
100 | ```
101 |
102 | 在这里,我们用到了几个特殊的宏。首先是`%.o:%.c`,这是一个模式规则,表示所有的`.o`目标都依赖于与它同名的`.c`文件(当然还有`deps`中列出的头文件)。再来就是命令部分的`$<`和`$@`,其中`$<`代表的是依赖关系表中的第一项(如果我们想引用的是整个关系表,那么就应该使用`$^`),具体到我们这里就是`%.c`。而`$@`代表的是当前语句的目标,即`%.o`。这样一来,`make`命令就会自动将所有的`.c`源文件编译成同名的`.o`文件。不用我们一项一项去指定了。整个代码自然简洁了许多。
103 |
104 | 到目前为止,我们已经有了一个不错的makefile文件了,至少用它来维护这个小型工程是没有什么问题了。当然,如果要进一步增加上面这个项目的可扩展性,我们就会需要用到一些Makefile语法中的**伪目标**和**函数规则**了。例如,如果我们想增加自动清理编译结果的功能就可以为其定义一个带伪目标的规则;
105 |
106 | ```makefile
107 | cc = gcc
108 | prom = calc
109 | deps = calc.h
110 | obj = main.o getch.o getop.o stack.o
111 |
112 | $(prom): $(obj)
113 | $(cc) -o $(prom) $(obj)
114 |
115 | %.o: %.c $(deps)
116 | $(cc) -c $< -o $@
117 |
118 | clean:
119 | rm -rf $(obj) $(prom)
120 | ```
121 |
122 | 有了上面最后两行代码,当我们在终端中执行`make clean`命令时,它就会去删除该工程生成的所有编译文件。
123 |
124 | 另外,如果我们需要往工程中添加一个`.c`或`.h`,可能同时就要再手动为obj常量再添加第一个`.o`文件,如果这列表很长,代码会非常难看,为此,我们需要用到Makefile中的函数,这里我们演示两个:
125 |
126 | ```makefile
127 | cc = gcc
128 | prom = calc
129 | deps = $(shell find ./ -name "*.h")
130 | src = $(shell find ./ -name "*.c")
131 | obj = $(src:%.c=%.o)
132 |
133 | $(prom): $(obj)
134 | $(cc) -o $(prom) $(obj)
135 |
136 | %.o: %.c $(deps)
137 | $(cc) -c $< -o $@
138 |
139 | clean:
140 | rm -rf $(obj) $(prom)
141 | ```
142 |
143 | 其中,shell函数主要用于执行shell命令,具体到这里就是找出当前目录下所有的`.c`和`.h`文件。而`$(src:%.c=%.o)`则是一个字符替换函数,它会将`src`所有的`.c`字串替换成`.o`,实际上就等于列出了所有`.c`文件要编译的结果。有了这两个设定,无论我们今后在该工程加入多少`.c`和`.h`文件,`Makefile`文件都能自动将其纳入到工程中来。
144 |
145 | ## A.3 请学习更多资料
146 |
147 | 到这里,我们就基本上将日常会用到的Makefile写法介绍了一遍。如果你想了解更多关于makefile和make的知识,请参考[GNU Make Manual](http://www.cs.utexas.edu/~cannata/cs345/GNU%20Make%20Manual.pdf)。[^2]
148 |
149 |
150 |
151 | [^1]:注释:即C语言的经典教程*The C Programming Language*,业界通常以其两位作者的首字母为缩写,将其简称为K&R C。
152 |
153 | [^2]:注释:下载链接:http://www.cs.utexas.edu/~cannata/cs345/GNU%20Make%20Manual.pdf
154 |
155 |
--------------------------------------------------------------------------------
/src/A2_附录B.md:
--------------------------------------------------------------------------------
1 | # 附录B:了解一下Node.js
2 |
3 | 考虑到本书介绍的gitbook和Hexo都要基于Node.js运行环境来部署,而这个运行环境如今已经形成了如此庞大的软件生态系统,我认为有必要在这里专门介绍一下Node.js以及它的安装和配置。换而言之,在接下来的内容中,我们首先会对Node.js做一个简单的概述,让读者了解一下这是怎样的一个运行环境,它的设计理念以及组件管理。然后,我们会具体演示Node.js在Windows、MacOS和Linux上的安装与配置。希望大家在阅读完这篇附录之后。能对Node.js运行环境有一个初步的认知,并能在自己的计算机上安装这个运行环境。
4 |
5 | ## B.1 Node.js概述
6 |
7 | 众所周知,JavaScript在很长一段时间内都被认为是一门只能依赖于浏览器的编程语言,这大大限制了这门优秀语言的使用范围。Node.js的出现改变了这一切,它是第一个能在服务器端运行JavaScript代码的、跨平台的运行环境,一举将JavaScript的应用领域扩展到了服务器端,使之释放出了巨大的生产力。
8 |
9 | 作为在服务器端运行的JavaScript环境,Node.js保留了JavaScript在浏览器端中所使用的大部分API,Node.js的作者Ryan Dahl并没有改变这门语言本身的任何特性,它的编程模型依旧将基于作用域和原型链这些概念,这让Node.js在服务器端上的应用具备了以下这些与众不同的特性:
10 |
11 | - **单一线程**:JavaScript单一线程的特性,与它最初只作用于浏览器有关。在浏览器中,JavaScript的主要作用是响应用户的操作并处理DOM。这决定了它只能以单一线程的方式来执行,否则会带来很复杂的同步问题。例如,如果我们在浏览器上用JavaScript同时执行了两个线程,一个线程负责在指定的DOM节点上添加内容,另一个线程则负责删除这个节点,这时浏览器应该以哪个线程为准?
12 |
13 | Node.js沿用了这种单一线程的执行特性。而且在Node.js中,JavaScript的执行线程与其他线程之间同样也是无法共享状态的。单一线程的最大好处是不用像多线程编程那样处理很容易产生bug的同步问题,它从根本上杜绝了死锁问题,也避免了线程上下文交换所带来的性能上的开销。当然了,单一线程的执行方式也有它自身的弱点,譬如,它无法充分发挥多核处理器的性能、一个错误就会导致整个程序崩溃,以及执行大量计算时会因长期占用处理器而影响其他异步I/O的执行。
14 |
15 | - **事件驱动**:在Web开发领域,JavaScript如今在浏览器端正承担了越来越重要的角色,其事件驱动的编程模型也逐渐深入人心。当然了,这种编程模型虽然具有轻量级、松耦合等优势,但在多个异步任务的场景下,由于程序中的各个事件是彼此独立的,它们之间的协作就成为了一个需要我们费心解决的问题。
16 |
17 | - **异步编程**:在Node.js中,大部分操作都是以异步调用的方式来进行的。Node.js的开发者们在其底层构建了许多异步I/O的API,包括文件读取、网络请求等。这样一来,我们就可以很自然地在语言层面上并行地执行I/O操作,这可以使得程序中的每个调用都无须等待之前的I/O调用结束,这带来了极大的效率提升。例如,如果我们想要读取两个相互不依赖的文件,如果采用的是异步I/O,其耗费的时间只取决于读取较慢的那个文件,而如果采用同步I/O的话,其耗时就是两个文件的读取时间之和了,异步操作模型带来的优势是显而易见的。
18 |
19 | 除此之外,Node.js对回调函数的支持也是其一大特色。回调函数是执行异步调用并接收其返回数据的最佳方式,当然了,这种方式也会导致代码的编写顺序与其具体执行顺序的不一致,对于很多习惯同步思路编程的人来说,阅读这样的代码会是一个不小的挑战。另外在流程控制方面,也会由于程序中穿插了各种异步方法和回调函数,它也远没有常规的同步方式那么一目了然,这也会给我们对程序的理解和调试带来一定的麻烦。
20 |
21 | 以上这些之所以被叫做特性,是因为它们实际上都是一些在已有技术上所做的取舍,了解它们的目的,就是为了让我们在考虑是否基于Node.js来开发相关应用时有自己的取舍。两者的取舍一致,譬如开发一些数据密集型、分布式实时应用程序,这些特性就会成为优势,但如果两者的取舍不一致,譬如开发一些需要大量计算、可靠性要求极高的程序,这些特性就会成为劣势。所以,只有了解自己手里的工具,我们才能做到事半功倍。
22 |
23 | ## B.2 Node.js的安装
24 |
25 | Node.js的安装主要有两种方式,通常在Windows和MacOS下,我们会采用下载`.msi`和`.pkg`格式的安装包,使用安装向导来进行安装。而在Linux和FreeBSD这一类系统中,我们则往往会采用apt和yum这样的包管理器来安装。这两种方式都不复杂,下面以Windows和Ubuntu为代表,简单介绍一下这两种安装方法。
26 |
27 | ### B.2.1 使用安装包
28 |
29 | 在Windows下想要安装Node.js,首先要选择一个合适的版本。打开Node.js的官网`https://nodejs.org/`,我们会看到有LTS和Current两种版本可供下载。LTS版即受到长期支持的版本,其组件通常都经历过了充分的测试,比较稳定,适合于正式的生产开发。而Current版本则是最新的版本,通常包含了最新纳入的新特性,比较适合想对Node.js本身进行研究的朋友。
30 |
31 | 
32 |
33 | 下载完`.msi`格式的安装包之后,我们就可以打开安装包启动安装向导了。在安装的开始阶段,安装向导会要求我们设置一些选项,大多数时候只需采用默认选项,直接点击「Next」即可。只是在组件选择的页面中,需要注意一下,如果你对Node.js的组件并不熟悉,最好选择安装全部组件。另外,请记得点开下图中那个「add path」选项前面的+号,这样安装程序就会主动把NodeJS和NPM这两个模块的命令路径添加到系统环境变量里,这对初学者来说是非常方便的。
34 |
35 | 
36 |
37 | 待一切选项设置完成之后,我们就可以点击下面的「Install」即可完成安装。
38 |
39 | 
40 |
41 | 如果一切顺利,我们在Windows中打开`cmd`终端,在其中输入`node -v`命令并回车之后,应该就会看到相关的版本信息。
42 |
43 | 
44 |
45 | ### B.2.2 使用包管理器
46 |
47 | 在Ubuntu这类Linux操作系统中,我们安装软件往往都会选择使用apt这一类的包管理器,简单而方便,依次执行以下命令即可:
48 |
49 | ```bash
50 | sudo apt update
51 | sudo apt install nodejs
52 | # 最新的Node.js已经集成了npm,所以某些情况下是无需单独安装npm的,这具体还要取决于你使用的软件源。
53 | sudo apt install npm
54 | ```
55 |
56 | 除此之外,我们还能安装n管理器来管理Node.js的版本,其安装命令如下:
57 |
58 | ```bash
59 | sudo npm install -g n
60 | ```
61 |
62 | 该工具的具体使用方式如下:
63 |
64 | ```bash
65 | sudo n lts # 长期支持
66 | sudo n stable # 稳定版
67 | sudo n latest # 最新版
68 | sudo n 12.4.0 # 直接指定版本
69 | sudo n # 使用上下键切换已有版本
70 | ```
71 |
72 | 同样的,如果一切顺利,我们打开命令行终端,并在其中输入`node -v`命令并回车之后,应该就会看到相关的版本信息。
73 |
74 | ## B.3 请学习更多资料
75 |
76 | 需要再次强调的是,我们在这里只是对Node.js做了一个最基本的介绍,并帮助你安装了这个运行环境。但Node.js是一个非常庞大的开源软件生态系统,它的涉猎范围从Web开发,到服务器后端程序,到PC端桌面应用、移动端应用,几乎无所不包。除此之外,它也将JavaScript这门原本只依附于浏览器的脚本语言变成了近乎全能的编程语言,在编程领域中的意义重大,值得我们阅读更多的资料来了解它、学习它、使用它。
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/img/0-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/0-0.jpg
--------------------------------------------------------------------------------
/src/img/1-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/1-1.jpg
--------------------------------------------------------------------------------
/src/img/2-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-1.png
--------------------------------------------------------------------------------
/src/img/2-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-10.png
--------------------------------------------------------------------------------
/src/img/2-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-11.png
--------------------------------------------------------------------------------
/src/img/2-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-12.png
--------------------------------------------------------------------------------
/src/img/2-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-13.png
--------------------------------------------------------------------------------
/src/img/2-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-14.png
--------------------------------------------------------------------------------
/src/img/2-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-15.png
--------------------------------------------------------------------------------
/src/img/2-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-16.png
--------------------------------------------------------------------------------
/src/img/2-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-17.png
--------------------------------------------------------------------------------
/src/img/2-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-18.png
--------------------------------------------------------------------------------
/src/img/2-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-19.png
--------------------------------------------------------------------------------
/src/img/2-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-2.png
--------------------------------------------------------------------------------
/src/img/2-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-20.png
--------------------------------------------------------------------------------
/src/img/2-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-3.png
--------------------------------------------------------------------------------
/src/img/2-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-4.png
--------------------------------------------------------------------------------
/src/img/2-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-5.png
--------------------------------------------------------------------------------
/src/img/2-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-6.png
--------------------------------------------------------------------------------
/src/img/2-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-7.png
--------------------------------------------------------------------------------
/src/img/2-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-8.png
--------------------------------------------------------------------------------
/src/img/2-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/2-9.png
--------------------------------------------------------------------------------
/src/img/3-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-1.png
--------------------------------------------------------------------------------
/src/img/3-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-10.png
--------------------------------------------------------------------------------
/src/img/3-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-11.png
--------------------------------------------------------------------------------
/src/img/3-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-12.png
--------------------------------------------------------------------------------
/src/img/3-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-13.png
--------------------------------------------------------------------------------
/src/img/3-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-14.png
--------------------------------------------------------------------------------
/src/img/3-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-15.png
--------------------------------------------------------------------------------
/src/img/3-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-16.png
--------------------------------------------------------------------------------
/src/img/3-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-17.png
--------------------------------------------------------------------------------
/src/img/3-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-18.png
--------------------------------------------------------------------------------
/src/img/3-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-19.png
--------------------------------------------------------------------------------
/src/img/3-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-2.png
--------------------------------------------------------------------------------
/src/img/3-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-20.png
--------------------------------------------------------------------------------
/src/img/3-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-21.png
--------------------------------------------------------------------------------
/src/img/3-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-22.png
--------------------------------------------------------------------------------
/src/img/3-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-23.png
--------------------------------------------------------------------------------
/src/img/3-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-3.png
--------------------------------------------------------------------------------
/src/img/3-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-4.png
--------------------------------------------------------------------------------
/src/img/3-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-5.png
--------------------------------------------------------------------------------
/src/img/3-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-6.png
--------------------------------------------------------------------------------
/src/img/3-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-7.png
--------------------------------------------------------------------------------
/src/img/3-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-8.png
--------------------------------------------------------------------------------
/src/img/3-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/3-9.png
--------------------------------------------------------------------------------
/src/img/4-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-1.png
--------------------------------------------------------------------------------
/src/img/4-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-2.png
--------------------------------------------------------------------------------
/src/img/4-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-3.png
--------------------------------------------------------------------------------
/src/img/4-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-4.png
--------------------------------------------------------------------------------
/src/img/4-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-5.png
--------------------------------------------------------------------------------
/src/img/4-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/4-6.png
--------------------------------------------------------------------------------
/src/img/5-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-1.png
--------------------------------------------------------------------------------
/src/img/5-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-10.png
--------------------------------------------------------------------------------
/src/img/5-11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-11.jpg
--------------------------------------------------------------------------------
/src/img/5-12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-12.jpg
--------------------------------------------------------------------------------
/src/img/5-13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-13.jpg
--------------------------------------------------------------------------------
/src/img/5-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-14.png
--------------------------------------------------------------------------------
/src/img/5-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-15.png
--------------------------------------------------------------------------------
/src/img/5-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-16.png
--------------------------------------------------------------------------------
/src/img/5-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-17.png
--------------------------------------------------------------------------------
/src/img/5-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-18.png
--------------------------------------------------------------------------------
/src/img/5-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-19.png
--------------------------------------------------------------------------------
/src/img/5-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-2.png
--------------------------------------------------------------------------------
/src/img/5-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-20.png
--------------------------------------------------------------------------------
/src/img/5-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-21.png
--------------------------------------------------------------------------------
/src/img/5-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-22.png
--------------------------------------------------------------------------------
/src/img/5-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-23.png
--------------------------------------------------------------------------------
/src/img/5-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-24.png
--------------------------------------------------------------------------------
/src/img/5-25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-25.png
--------------------------------------------------------------------------------
/src/img/5-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-26.png
--------------------------------------------------------------------------------
/src/img/5-27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-27.png
--------------------------------------------------------------------------------
/src/img/5-28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-28.png
--------------------------------------------------------------------------------
/src/img/5-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-29.png
--------------------------------------------------------------------------------
/src/img/5-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-3.png
--------------------------------------------------------------------------------
/src/img/5-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-4.png
--------------------------------------------------------------------------------
/src/img/5-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-6.png
--------------------------------------------------------------------------------
/src/img/5-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-7.png
--------------------------------------------------------------------------------
/src/img/5-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/5-9.png
--------------------------------------------------------------------------------
/src/img/6-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-1.png
--------------------------------------------------------------------------------
/src/img/6-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-10.png
--------------------------------------------------------------------------------
/src/img/6-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-11.png
--------------------------------------------------------------------------------
/src/img/6-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-12.png
--------------------------------------------------------------------------------
/src/img/6-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-13.png
--------------------------------------------------------------------------------
/src/img/6-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-14.png
--------------------------------------------------------------------------------
/src/img/6-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-15.png
--------------------------------------------------------------------------------
/src/img/6-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-16.png
--------------------------------------------------------------------------------
/src/img/6-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-17.png
--------------------------------------------------------------------------------
/src/img/6-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-18.png
--------------------------------------------------------------------------------
/src/img/6-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-19.png
--------------------------------------------------------------------------------
/src/img/6-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-2.png
--------------------------------------------------------------------------------
/src/img/6-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-20.png
--------------------------------------------------------------------------------
/src/img/6-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-21.png
--------------------------------------------------------------------------------
/src/img/6-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-22.png
--------------------------------------------------------------------------------
/src/img/6-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-23.png
--------------------------------------------------------------------------------
/src/img/6-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-24.png
--------------------------------------------------------------------------------
/src/img/6-25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-25.png
--------------------------------------------------------------------------------
/src/img/6-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-3.png
--------------------------------------------------------------------------------
/src/img/6-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-4.png
--------------------------------------------------------------------------------
/src/img/6-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-5.png
--------------------------------------------------------------------------------
/src/img/6-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-6.png
--------------------------------------------------------------------------------
/src/img/6-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-7.png
--------------------------------------------------------------------------------
/src/img/6-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-8.png
--------------------------------------------------------------------------------
/src/img/6-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/6-9.png
--------------------------------------------------------------------------------
/src/img/AB-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/AB-1.png
--------------------------------------------------------------------------------
/src/img/AB-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/AB-2.png
--------------------------------------------------------------------------------
/src/img/AB-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/AB-3.png
--------------------------------------------------------------------------------
/src/img/AB-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/AB-4.png
--------------------------------------------------------------------------------
/src/img/lingjie_photo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/img/lingjie_photo.jpg
--------------------------------------------------------------------------------
/src/makefile:
--------------------------------------------------------------------------------
1 | # 作者:owlman
2 | # 时间:2018年10月22日
3 | # 作用:将markdown文件转换成docx格式
4 |
5 | src = $(shell find ./ -name "*.md")
6 | docx = $(src:%.md=../docx/%.docx)
7 |
8 | all: $(docx)
9 | ls -l ../docx
10 |
11 | ../docx/%.docx:%.md
12 | pandoc -f markdown+tex_math_dollars -t docx $< -o $@ --reference-doc=./styles/styles.docx --pdf-engine=xelatex
13 |
14 | clean:
15 | rm -rf $(docx)
--------------------------------------------------------------------------------
/src/styles/styles.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owlman/markdown_guide/3620ca94a05f7b4f1cf2d2ae940ffa33206aed6c/src/styles/styles.docx
--------------------------------------------------------------------------------
/src/作者简介.md:
--------------------------------------------------------------------------------
1 | # 作者简介
2 |
3 |
4 |
5 | 
6 |
7 |
8 |
9 | 凌杰:浙江大学远程教育学院“荣誉学员”、2012年度“十大远程骄子”。目前为自由软件开发者。精通C/C++、Python、JavaScript等多门编程语言,拥有丰富的软件开发及测试经验。个人崇尚黑客文化,支持开源运动,时常出没于国内外各种技术社区,曾担任上海交通大学饮水思源BBS的技术区区长,并兼任该区C/C++板板主多年。近些年来还参与了多本计算机技术类外文书籍的翻译工作,译作包括《Python算法教程》、《JavaScript面向对象编程指南》、《元素模式》等。
10 |
11 |
12 |
13 | ---
14 |
15 | ## 联系方式
16 |
17 | - 个人主页:http://owlman.org/
18 | - 新浪微博:https://weibo.com/owlman
19 | - 电子邮件:[lingjiexyz@hotmail.com](mailto:lingjiexyz@hotmail.com)
20 |
--------------------------------------------------------------------------------
|