0%

分为语法和工具两个部分,备忘录。

语法

写在前面

在使用 JotterPad(CommonMark)阅读 markdown 格式的文本时,发现的细节:

  1. 标题 # 后需要有空格,才能解析成标题,不然就是文本;【重要】

    • 进一步修正:任意级别的标题行前后添加空行,至少标题行之前要有空行,# 之后添加空格;
  2. 使用参考式链接时,链接网址只能放在文件最末尾,不然识别不出来;【重要】

  3. 引用内使用编号问题:

    引用文字

    1. item1
    2. item

    编号结束,结尾的引用文字

  4. 怎么写代码块?——是解析的,只不过呈现方式只体现在字体上,排版效果并不明显。

  5. 尽量不要嵌套使用。在 GitHub 上项目的 README.md 都不复杂。占一屏幕,不需要滚屏。 建议很值得采纳,但实在是不实用。

  6. 可以做图片链接的哦,惊喜

  7. 嵌套时无需有空行(分段需求除外,比如引用时),当两个模块是平行关系时需要有空行(列表除外,列表项之间添加空行会引入 <p>)。参考 1.1 节

  8. 中英文混合排版加不加空格问题,持保留态度,无论加或者不加,都保持原状。

    1. 强调语义,不加;强调呈现,添加。

    2. 书写笔记不考虑纯手工补充空格,为了表现效果美观吹毛求疵,时间成本太高,没有意义。【重要】

      扩展阅读:

  9. 测试 item

块元素

模块之间的嵌套使用,怎么书写是规范的一直是一件比较困惑的事情。但在我写下这篇文字的时候,我已经感觉到胜利在朝我招手了。

首先一定要有意识区分“块元素(Block Element)”和“Span Element”,对于熟悉 html 的程序员来说可能是很 easy 的一件事情,但是虽然我用 Markdown 两三个月,相关的操作手册、语法说明也看了很多,但我是自动过滤这两个单词的,讲解标题(用不同数目的 # 区分标题级别)和强调(用 * 斜体,** 加粗)时肯定是分别放在 Block Element 和 Span Element 中介绍,但我脑子里是没有这两个概念的,我并未意识到它们意味着什么,甚至并未意识到它们的存在。我真的是个前端白痴,原谅我。

  1. 块元素(Block Element)包括:

    • 标题
    • 引用
    • 列表,注意是整个列表,而不是列表的 item
    • 代码块
    • 分割线
  2. Span Element 包括:

    • 链接
    • 强调
    • 代码
    • 图片

块元素是涉及嵌套的主体!Span Element 不是。所以嵌套问题是块元素的嵌套问题,额,如果我了解 html 多好。

结论(针对 GFM)

秘籍:(在严格坚持第一点的基础上,除却以下情况不会用到第二点:如果问题出现在章节末尾(见本文末尾)、列表末尾,使用第二点)

  1. 每个独立的块元素(包括分段)之后留有空行,标题、分割线可以除外;

  2. 哪个块元素解析有问题,就在哪个块元素之前加空行;

    1. 为了保证一致性(特殊情形,即当前嵌套情形(列表主体除末尾空行无其他空行,且在末尾嵌套有子列表)),要求嵌套子列表时,子模块前添加空行(即本行之前的空行,否则解释时不完美);
  3. 综合上述两点,在每个块元素(包括分段)的前后添加空行可以保证所有情形下解释正确。唯一的不足在于阅读源文本时可能稍显松散。

  4. 其实,在每个块元素(包括分段、标题、分割线)之前留有空行是不是就万事大吉了呢?【重要】

详细描述:

  1. 分段用空行,这句是废话;

  2. 标题之前加空行,保证所有情况下语法正常解释;【重要】

    • 如果前置标题、分割线或者普通段落,则没有空行语法也能正常解释;
    • 如果前置列表、引用等,没有空行,语法解释后呈现有问题;
  3. 空行意味着引用、列表的结束;标题、分割线是单行的;GFM 中代码块是 ``` 结束的。多个空行合并成一个。

    • 分段时,空行意味着段落的结束;
    • 非分段情况下,段落之后不用跟空行。接标题、引用、列表、代码块都意味着段落结束。
    • 非分段情况下,段落之后无空行直接跟有序列表,是有问题的;直接跟无序列表没问题;
    • 综合上述三条,建议每个独立的块元素之后留有空行,标题、分割线除外【重要】
  4. 列表内容拥有缩进概念;

    • 列表 item 中缩进内容(针对引用、代码块)前(或者后)加空行;否则语法无法正常解释
    • 缩进内容为列表(即嵌套子列表)时,按照规则建议添加空行。即使无空行,语法也能正常解释,看着还顺眼一点
    • 综合上述两条,建议在嵌套子模块的结尾留有空行【重要】

补充说明:

  1. 列表的 item 之间一般不需要空行(分段除外),如果

    如果列表项之间有空行,markdown会给每一个生成的li元素创建一个p:

工具

前两年一直使用的 MarkdownPad2,后来随着系统更新(而软件并未跟进)出现了几项功能性问题,虽然也能通过某些手段结局,但无疑是影响体验的。

MarkdownPad 2 使用问题

在此基础上,由于对 Visual Studio Code 好奇心(喜新厌旧嘛),放弃了使用 MarkdownPad2,但回头再看(2020/12/25 17:38:28 )前者也只那些 vimer 的狂欢,经过各种调教之后可能好用,但调教本身也是成本。

快捷键支持并不完全。还是算了。来源

深有感触,不胜其烦。所以又回归了 MarkdownPad2

这两天工作上用到了 grep、sed、awk 文本处理命令。有心在业余时间花心思多掌握一些,在此前提下,发现熟悉正则表达式是很重要的。

正则表达式

查阅维基百科,发现其中文词条 正则表达式 没有价值,个别的知识点即便有效也充斥在大量的垃圾信息里,此词条好似百度百科的众多词条,灌水横拉硬拽拼凑而成,或源于翻译英文词条时偷懒挑肥拣瘦,只翻译了一部分内容,却篡改章节目录造成“不成文”的感受。

其英文词条 Regular expression 相对“丰满”一些,看目录至少提到了不同标准、不同流派,比中文词条要好。

参考 正则表达式“派别”简述正则表达式 流派(flavor)及差异简介,都明确指出了三种:

  • BRE: Basic Regular Expression
  • ERE: Extended Regular Express
  • PCRE: Perl Compatible Regular Expression

其中,前两者都是 POSIX: Portable Operating System Interface 的规范。

常见的编程语言中使用正则表达式的记法,其实都源于 Perl。

现在的编程语言中的正则表达式,大部分都属于 PCRE 这个分支。

常见的正则表达式记法,其实都源于 Perl

但在 POSIX 的系统上,有关的工具使用正则表达式,其记法与上述不同,大都要落于 BRE、ERE 这两者之中:

- 使用BRE语法的命令有:grep、ed、sed、vim

- 使用ERE语法的命令有:egrep、awk、emacs

需要补充的一点是,在 linux 上有关工具对 BRE、ERE 语法是进行过扩充的,好比对 C 语言标准、C++ 语言标准进行的诸多 GNU 扩展。在 Linux/Unix 工具与正则表达式的 POSIX 规范 中有提到 GNU 扩展的相关内容,在 正则表达式“派别”简述 讲述 POSIX 标准时也提到了 GNU 扩展。

GNU 在实现了 POXIS 标准的同时,做了一定的扩展

PCRE

PCRE(Perl Compatible Regular Expression):可以说是正则表达式的老前辈(niel 注:需考证),它是从 Perl 衍生出来的一个显赫流派,\d \w \s 等表示法就是它的特征;

BRE

BRE(Basic Regular Expression):POSIX 规范的正则表达式之一,grep、vi、sed 都属于这一派,它显著的特征就是 ( ) { } 这几个括号元字符必须经过转义才具有特殊含义,不支持 + ? | 等元字符,随着时间发展,后来又出现了 GNU BRE,GNU BRE 支持上边这些字符,但是也必须都经过转义才能有特殊含义;

ERE

ERE(Extended Regular Express):也是 POSIX 规范的正则表达式之一,egrep awk 都属于这一派,( ) { } + ? | 等元字符可以直接使用不需要转义,这个流派后来也出现了 GNU ERE,在之前的基础上添加了支持 \1 \2 等。

参考

不明觉厉的 各种语言或工具软件的不同风格的正则表达式文法规定

如果更关注使用有关工具时的细节,可以参考 Linux 中常用文本工具与正则表达式的关系 。更多的语法细节还是要在用到的时候仔细查阅。

引擎 正则表达式引擎及其分类

55分钟学会正则表达式 学习笔记

建议看原文(英文)比较好,译者也给出了原文的链接。翻译时译者不够细心,和原文相比有好几处错误,有的是很明显的上下文冲突,所以觉得译者根本就不用心。

前言部分,简单描述正则表达式是什么;之后讲解正则表达式的基础语法。

  • 正则表达式有可能出现语法错误——不是所有的字符串都是正则表达式

字符

理解“元字符”概念。

普通字符只能匹配它们本身;元字符可以匹配一些特殊规则。使用反斜杠 \ 可以忽略元字符,使得元字符的功能与普通字符一样。

点“.”

匹配任意一个字符

字符类

字符类是一组在方括号内的字符,表示可以匹配其中的任何一个字符。

重要提示:字符类中和字符类外的规则有时不同,一些字符在字符类中是元字符,在字符类外是普通字符。一些字符正好相反。还有一些字符在字符类中和字符类外都是元字符,这要视情况而定!

字符类的范围

在字符类中,你可以通过使用短横线来表示匹配字母或数字的范围。

字符类的反义

你可以在字符类的起始位放一个反义符 ^

Freebie character classes

译者翻译为“转义字符类”,个人觉得不能够表达原作的味道。参考上下文及“freebie”单词原意,应该是要表达,和某些字符类表示相同意义的转义字符。

下文中Freebie multipliers 译为“关于重复的转义字符”。类比,此处译为“关于字符类的转义字符”就会好很多。

  • \d:[0-9]
  • \w:[0-9A-Za-z_]
  • \s:匹配一个空字符(空格,制表符,回车或者换行)
  • \D:[^0-9]
  • \W:[^0-9A-Za-z]
  • \S:匹配一个非空字符

重复

在字符或字符集之后,你可以使用 { } 大括号来表示重复

指定重复次数范围

Freebie multipliers

  • ?:{0,1},重复0次或1次
  • *:{0,},重复任意次(0次、1次或多次)
  • +:{1,},重复1次以上(包括1次)

当一条声明语句中包含多个指针,或者混用数组的时候,每每傻傻分不清。

变量定义

在《C++ Primer》P38 页,2.2 节中描述到

变量定义的基本形式是:首先是类型说明符(type specifier),随后紧跟由一个或多个变量名组成的列表,其中变量名以逗号分隔,最后以分号结束。

列表中每个变量名的类型都由类型说明符指定,定义时还可以为一个或多个变量赋初值:int a=0, b, c=3;

ps:稍后再对变量的定义和声明做区分,对于初始化和赋值做区分。

复合类型

P45 页,2.3 节描述如下

一个简单的声明语句由……。更通用的描述是,一条声明语句由一个基本数据类型(base-type)和紧随其后的一个声明符(declarator)列表组成。每个声明符命名了一个变量并指定该变量为与基本数据类型有关的某种类型。

P51 页

在同一条定义语句中个,虽然基本数据类型只有一个,但是声明符的形式却可以不同。也就是说,一条定义语句可能定义出不同类型的变量。

1
2
// i是一个int型的数,p是一个int型指针,r是一个int型引用。
int i = 1024, *p = &i, &r =i;

P53 页

面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清楚它的真实含义。

1
int *p, *&r = p;  // r是一个对指针p的引用

数组是一种复合类型 (P101页)

数组中元素的个数也属于数组类型的一部分。

P102 页

默认情况下,类型修饰符从右向左依次绑定。理解复杂的数组声明,由内向外,从右向左。

1
2
3
int *ptrs[10];  		// ptrs是含有10个元素的数组,数组元素是int型指针
int *(&array)[10] = ptr; // array是数组的引用,该数组含有10个指针
int (*Parray)[10]; // Parray是一个指针,指向一个含有10个整数的数组

const 限定符

reference to const,对常量的引用;不存在 const reference,因为引用不是对象。

1
2
const int ci = 1.24;
const int &r1 = ci;

pointer to const,指向常量的指针;const pointer,指针本身是常量。

* 放在 const 关键字之前用以说明指针是一个常量。

1
2
const double pi = 3.1415;
const double *const pip = &pi;

要想弄清楚这些生命的含义最行之有效的方法是从右向左阅读。