Skip to content

Commit 864ef22

Browse files
committed
see changkun#12: fix pandoc build fail because of regex
1 parent 507f8b9 commit 864ef22

File tree

6 files changed

+146
-36
lines changed

6 files changed

+146
-36
lines changed

book/en-us/06-regex.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,91 @@ and then introduces the use of the regular expression library
136136
through a practical example based on the main requirements of
137137
using regular expressions.
138138
139+
## Exercise
140+
141+
In web server development, we usually want to serve some routes that satisfy a certain condition.
142+
Regular expressions are one of the tools to accomplish this.
143+
Given the following request structure:
144+
145+
```cpp
146+
struct Request {
147+
// request method, POST, GET; path; HTTP version
148+
std::string method, path, http_version;
149+
// use smart pointer for reference counting of content
150+
std::shared_ptr<std::istream> content;
151+
// hash container, key-value dict
152+
std::unordered_map<std::string, std::string> header;
153+
// use regular expression for path match
154+
std::smatch path_match;
155+
};
156+
```
157+
158+
Requested resource type:
159+
160+
```cpp
161+
typedef std::map<
162+
std::string, std::unordered_map<
163+
std::string,std::function<void(std::ostream&, Request&)>>> resource_type;
164+
```
165+
166+
And server template:
167+
168+
```cpp
169+
template <typename socket_type>
170+
class ServerBase {
171+
public:
172+
resource_type resource;
173+
resource_type default_resource;
174+
175+
void start() {
176+
// TODO
177+
}
178+
protected:
179+
Request parse_request(std::istream& stream) const {
180+
// TODO
181+
}
182+
}
183+
```
184+
185+
Please implement the member functions `start()` and `parse_request`. Enable server template users to specify routes as follows:
186+
187+
```cpp
188+
template<typename SERVER_TYPE>
189+
void start_server(SERVER_TYPE &server) {
190+
191+
// process GET request for /match/[digit+numbers], e.g. GET request is /match/abc123, will return abc123
192+
server.resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
193+
string number=request.path_match[1];
194+
response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length() << "\r\n\r\n" << number;
195+
};
196+
197+
// peocess default GET request; anonymous function will be called if no other matches
198+
// response files in folder web/
199+
// default: index.html
200+
server.default_resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
201+
string filename = "www/";
202+
203+
string path = request.path_match[1];
204+
205+
// forbidden use `..` access content outside folder web/
206+
size_t last_pos = path.rfind(".");
207+
size_t current_pos = 0;
208+
size_t pos;
209+
while((pos=path.find('.', current_pos)) != string::npos && pos != last_pos) {
210+
current_pos = pos;
211+
path.erase(pos, 1);
212+
last_pos--;
213+
}
214+
215+
// (...)
216+
};
217+
218+
server.start();
219+
}
220+
```
221+
222+
An suggested solution can be found [here](../../exercises/6).
223+
139224
[Table of Content](./toc.md) | [Previous Chapter](./05-pointers.md) | [Next Chapter: Threads and Concurrency](./07-thread.md)
140225

141226
## Further Readings

book/zh-cn/04-containers.md

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ order: 4
1010
1111
[TOC]
1212

13-
## 4.1 std::array 和 std::forward\_list
13+
## 4.1 `std::array``std::forward_list`
1414

15-
### std::array
15+
### `std::array`
1616

1717
看到这个容器的时候肯定会出现这样的问题:
1818

1919
1. 为什么要引入 `std::array` 而不是直接使用 `std::vector`
2020
2. 已经有了传统数组,为什么要用 `std::array`?
2121

22-
先回答第一个问题,与 `std::vector` 不同,`std::array` 对象的大小是固定的,如果容器大小是固定的,那么可以优先考虑使用 `std::array` 容器。另外由于 `std::vector` 是自动扩容的,当存入大量的数据后,并且对容器进行了删除操作,容器并不会自动归还被删除元素相应的内存,这时候就需要手动运行 `shrink_to_fit()` 释放这部分内存。
22+
先回答第一个问题,与 `std::vector` 不同,`std::array` 对象的大小是固定的,如果容器大小是固定的,那么可以优先考虑使用 `std::array` 容器。
23+
另外由于 `std::vector` 是自动扩容的,当存入大量的数据后,并且对容器进行了删除操作,
24+
容器并不会自动归还被删除元素相应的内存,这时候就需要手动运行 `shrink_to_fit()` 释放这部分内存。
2325

2426
```cpp
2527
std::vector<int> v;
@@ -98,21 +100,28 @@ foo(arr.data(), arr.size());
98100
std::sort(arr.begin(), arr.end());
99101
```
100102

101-
### std::forward\_list
103+
### `std::forward_list`
102104

103105
`std::forward_list` 是一个列表容器,使用方法和 `std::list` 基本类似,因此我们就不花费篇幅进行介绍了。
104106

105-
需要知道的是,和 `std::list` 的双向链表的实现不同,`std::forward_list` 使用单向链表进行实现,提供了 `O(1)` 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 `size()` 方法的容器。当不需要双向迭代时,具有比 `std::list` 更高的空间利用率。
107+
需要知道的是,和 `std::list` 的双向链表的实现不同,`std::forward_list` 使用单向链表进行实现,
108+
提供了 `O(1)` 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),
109+
也是标准库容器中唯一一个不提供 `size()` 方法的容器。当不需要双向迭代时,具有比 `std::list` 更高的空间利用率。
106110

107111
## 4.2 无序容器
108112

109-
我们已经熟知了传统 C++ 中的有序容器 `std::map`/`std::set`,这些元素内部通过红黑树进行实现,插入和搜索的平均复杂度均为 `O(log(size))`。在插入元素时候,会根据 `<` 操作符比较元素大小并判断元素是否相同,并选择合适的位置插入到容器中。当对这个容器中的元素进行遍历时,输出结果会按照 `<` 操作符的顺序来逐个遍历。
113+
我们已经熟知了传统 C++ 中的有序容器 `std::map`/`std::set`,这些元素内部通过红黑树进行实现,
114+
插入和搜索的平均复杂度均为 `O(log(size))`。在插入元素时候,会根据 `<` 操作符比较元素大小并判断元素是否相同,
115+
并选择合适的位置插入到容器中。当对这个容器中的元素进行遍历时,输出结果会按照 `<` 操作符的顺序来逐个遍历。
110116

111-
而无序容器中的元素是不进行排序的,内部通过 Hash 表实现,插入和搜索元素的平均复杂度为 `O(constant)`,在不关心容器内部元素顺序时,能够获得显著的性能提升。
117+
而无序容器中的元素是不进行排序的,内部通过 Hash 表实现,插入和搜索元素的平均复杂度为 `O(constant)`
118+
在不关心容器内部元素顺序时,能够获得显著的性能提升。
112119

113-
C++11 引入了两组无序容器:`std::unordered_map`/`std::unordered_multimap``std::unordered_set`/`std::unordered_multiset`
120+
C++11 引入了两组无序容器:`std::unordered_map`/`std::unordered_multimap`
121+
`std::unordered_set`/`std::unordered_multiset`
114122

115-
它们的用法和原有的 `std::map`/`std::multimap`/`std::set`/`set::multiset` 基本类似,由于这些容器我们已经很熟悉了,便不一一举例,我们直接来比较一下`std::map``std::unordered_map`
123+
它们的用法和原有的 `std::map`/`std::multimap`/`std::set`/`set::multiset` 基本类似,
124+
由于这些容器我们已经很熟悉了,便不一一举例,我们直接来比较一下`std::map``std::unordered_map`
116125

117126
```cpp
118127
#include <iostream>
@@ -147,7 +156,7 @@ int main() {
147156

148157
最终的输出结果为:
149158

150-
```
159+
```txt
151160
std::unordered_map
152161
Key:[2] Value:[2]
153162
Key:[3] Value:[3]
@@ -159,9 +168,11 @@ Key:[2] Value:[2]
159168
Key:[3] Value:[3]
160169
```
161170

162-
## 4.3 元组 std::tuple
171+
## 4.3 元组 `std::tuple`
163172

164-
了解过 Python 的程序员应该知道元组的概念,纵观传统 C++ 中的容器,除了 `std::pair` 外,似乎没有现成的结构能够用来存放不同类型的数据(通常我们会自己定义结构)。但 `std::pair` 的缺陷是显而易见的,只能保存两个元素。
173+
了解过 Python 的程序员应该知道元组的概念,纵观传统 C++ 中的容器,除了 `std::pair` 外,
174+
似乎没有现成的结构能够用来存放不同类型的数据(通常我们会自己定义结构)。
175+
`std::pair` 的缺陷是显而易见的,只能保存两个元素。
165176

166177
### 元组基本操作
167178

@@ -267,7 +278,8 @@ std::cout << tuple_index(t, i) << std::endl;
267278
auto new_tuple = std::tuple_cat(get_student(1), std::move(t));
268279
```
269280

270-
马上就能够发现,应该如何快速遍历一个元组?但是我们刚才介绍了如何在运行期通过非常数索引一个 `tuple` 那么遍历就变得简单了,首先我们需要知道一个元组的长度,可以:
281+
马上就能够发现,应该如何快速遍历一个元组?但是我们刚才介绍了如何在运行期通过非常数索引一个 `tuple` 那么遍历就变得简单了,
282+
首先我们需要知道一个元组的长度,可以:
271283

272284
```cpp
273285
template <typename T>

book/zh-cn/05-pointers.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,30 @@ order: 5
1212

1313
## 5.1 RAII 与引用计数
1414

15-
了解 `Objective-C`/`Swift` 的程序员应该知道引用计数的概念。引用计数这种计数是为了防止内存泄露而产生的。基本想法是对于动态分配的对象,进行引用计数,每当增加一次对同一个对象的引用,那么引用对象的引用计数就会增加一次,每删除一次引用,引用计数就会减一,当一个对象的引用计数减为零时,就自动删除指向的堆内存。
15+
了解 `Objective-C`/`Swift` 的程序员应该知道引用计数的概念。引用计数这种计数是为了防止内存泄露而产生的。
16+
基本想法是对于动态分配的对象,进行引用计数,每当增加一次对同一个对象的引用,那么引用对象的引用计数就会增加一次,
17+
每删除一次引用,引用计数就会减一,当一个对象的引用计数减为零时,就自动删除指向的堆内存。
1618

17-
在传统 C++ 中,『记得』手动释放资源,总不是最佳实践。因为我们很有可能就忘记了去释放资源而导致泄露。所以通常的做法是对于一个对象而言,我们在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间,也就是我们常说的 RAII 资源获取即初始化技术。
19+
在传统 C++ 中,『记得』手动释放资源,总不是最佳实践。因为我们很有可能就忘记了去释放资源而导致泄露。
20+
所以通常的做法是对于一个对象而言,我们在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间,
21+
也就是我们常说的 RAII 资源获取即初始化技术。
1822

19-
凡事都有例外,我们总会有需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 `new``delete` 去『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。这些智能指针就包括 `std::shared_ptr`/`std::unique_ptr`/`std::weak_ptr`,使用它们需要包含头文件 `<memory>`
23+
凡事都有例外,我们总会有需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 `new``delete`
24+
『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。
25+
这些智能指针就包括 `std::shared_ptr`/`std::unique_ptr`/`std::weak_ptr`,使用它们需要包含头文件 `<memory>`
2026

21-
> 注意:引用计数不是垃圾回收,引用计数能够尽快收回不再被使用的对象,同时在回收的过程中也不会造成长时间的等待,更能够清晰明确的表明资源的生命周期。
27+
> 注意:引用计数不是垃圾回收,引用计数能够尽快收回不再被使用的对象,同时在回收的过程中也不会造成长时间的等待,
28+
> 更能够清晰明确的表明资源的生命周期。
2229
23-
## 5.2 std::shared_ptr
30+
## 5.2 `std::shared_ptr`
2431

25-
`std::shared_ptr` 是一种智能指针,它能够记录多少个 `shared_ptr` 共同指向一个对象,从而消除显示的调用 `delete`,当引用计数变为零的时候就会将对象自动删除。
32+
`std::shared_ptr` 是一种智能指针,它能够记录多少个 `shared_ptr` 共同指向一个对象,从而消除显示的调用
33+
`delete`,当引用计数变为零的时候就会将对象自动删除。
2634

2735
但还不够,因为使用 `std::shared_ptr` 仍然需要使用 `new` 来调用,这使得代码出现了某种程度上的不对称。
2836

29-
`std::make_shared` 就能够用来消除显式的使用 `new`,所以`std::make_shared` 会分配创建传入参数中的对象,并返回这个对象类型的`std::shared_ptr`指针。例如:
37+
`std::make_shared` 就能够用来消除显式的使用 `new`,所以`std::make_shared` 会分配创建传入参数中的对象,
38+
并返回这个对象类型的`std::shared_ptr`指针。例如:
3039

3140
```cpp
3241
#include <iostream>
@@ -47,7 +56,8 @@ int main()
4756
}
4857
```
4958
50-
`std::shared_ptr` 可以通过 `get()` 方法来获取原始指针,通过 `reset()` 来减少一个引用计数,并通过`use_count()`来查看一个对象的引用计数。例如:
59+
`std::shared_ptr` 可以通过 `get()` 方法来获取原始指针,通过 `reset()` 来减少一个引用计数,
60+
并通过`use_count()`来查看一个对象的引用计数。例如:
5161
5262
```cpp
5363
auto pointer = std::make_shared<int>(10);
@@ -70,7 +80,7 @@ std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; //
7080
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 0, pointer3 已 reset
7181
```
7282

73-
## 5.3 std::unique_ptr
83+
## 5.3 `std::unique_ptr`
7484

7585
`std::unique_ptr` 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证代码的安全:
7686

@@ -79,7 +89,7 @@ std::unique_ptr<int> pointer = std::make_unique<int>(10); // make_unique 从 C++
7989
std::unique_ptr<int> pointer2 = pointer; // 非法
8090
```
8191

82-
> make_unique 并不复杂,C++11 没有提供 std::make_unique,可以自行实现:
92+
> `make_unique` 并不复杂,C++11 没有提供 `std::make_unique`,可以自行实现:
8393
>
8494
> ```cpp
8595
> template<typename T, typename ...Args>

book/zh-cn/06-regex.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ order: 6
1818
2. 将匹配的子串替换;
1919
3. 从某个串中取出符合条件的子串。
2020

21-
正则表达式是由普通字符(例如 a 到 z)以及特殊字符组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
21+
正则表达式是由普通字符(例如 a 到 z)以及特殊字符组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。
22+
正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
2223

2324

2425
### 普通字符
@@ -49,12 +50,12 @@ order: 6
4950

5051

5152
|字符|描述|
52-
|:---:|:------------------------------------------------------|
53-
|`*`|匹配前面的子表达式零次或多次。例如,`foo*` 能匹配 `fo` 以及 `foooo``*` 等价于`{0,}`|
54-
|`+`|匹配前面的子表达式一次或多次。例如,`foo+` 能匹配 `foo` 以及 `foooo`,但不能匹配 `fo``+` 等价于 `{1,}`|
55-
|`?`|匹配前面的子表达式零次或一次。例如,`Your(s)?` 可以匹配 `Your``Yours` 中的`Your``?` 等价于 `{0,1}`|
56-
|`{n}`| `n` 是一个非负整数。匹配确定的 `n` 次。例如,`o{2}` 不能匹配 `for` 中的 `o`,但是能匹配 `foo` 中的两个 `o`|
57-
|`{n,}`| `n` 是一个非负整数。至少匹配 `n` 次。例如,`o{2,}` 不能匹配 `for` 中的 `o`,但能匹配 `foooooo` 中的所有 `o``o{1,}` 等价于 `o+``o{0,}` 则等价于 `o*`|
53+
|:-----:|:------------------------------------------------------|
54+
|`*` |匹配前面的子表达式零次或多次。例如,`foo*` 能匹配 `fo` 以及 `foooo``*` 等价于`{0,}`|
55+
|`+` |匹配前面的子表达式一次或多次。例如,`foo+` 能匹配 `foo` 以及 `foooo`,但不能匹配 `fo``+` 等价于 `{1,}`|
56+
|`?` |匹配前面的子表达式零次或一次。例如,`Your(s)?` 可以匹配 `Your``Yours` 中的`Your``?` 等价于 `{0,1}`|
57+
|`{n}` | `n` 是一个非负整数。匹配确定的 `n` 次。例如,`o{2}` 不能匹配 `for` 中的 `o`,但是能匹配 `foo` 中的两个 `o`|
58+
|`{n,}` | `n` 是一个非负整数。至少匹配 `n` 次。例如,`o{2,}` 不能匹配 `for` 中的 `o`,但能匹配 `foooooo` 中的所有 `o``o{1,}` 等价于 `o+``o{0,}` 则等价于 `o*`|
5859
|`{n,m}`| `m``n` 均为非负整数,其中 `n` 小于等于 `m`。最少匹配 `n` 次且最多匹配 `m` 次。例如,`o{1,3}` 将匹配 `foooooo` 中的前三个 `o``o{0,1}` 等价于 `o?`。注意,在逗号和两个数之间不能有空格。|
5960

6061
有了这两张表,我们通常就能够读懂几乎所有的正则表达式了。
@@ -77,7 +78,10 @@ C++11 提供的正则表达式库操作 `std::string` 对象,
7778

7879
我们通过一个简单的例子来简单介绍这个库的使用。考虑下面的正则表达式:
7980

80-
- `[a-z]+\.txt`: 在这个正则表达式中, `[a-z]` 表示匹配一个小写字母, `+` 可以使前面的表达式匹配多次,因此 `[a-z]+` 能够匹配一个小写字母组成的字符串。在正则表达式中一个 `.` 表示匹配任意字符,而 `\.` 则表示匹配字符 `.`,最后的 `txt` 表示严格匹配 `txt` 则三个字母。因此这个正则表达式的所要匹配的内容就是由纯小写字母组成的文本文件。
81+
- `[a-z]+\.txt`: 在这个正则表达式中, `[a-z]` 表示匹配一个小写字母, `+` 可以使前面的表达式匹配多次,
82+
因此 `[a-z]+` 能够匹配一个小写字母组成的字符串。
83+
在正则表达式中一个 `.` 表示匹配任意字符,而 `\.` 则表示匹配字符 `.`
84+
最后的 `txt` 表示严格匹配 `txt` 则三个字母。因此这个正则表达式的所要匹配的内容就是由纯小写字母组成的文本文件。
8185

8286
`std::regex_match` 用于匹配字符串和正则表达式,有很多不同的重载形式。
8387
最简单的一个形式就是传入 `std::string` 以及一个 `std::regex` 进行匹配,
@@ -90,7 +94,7 @@ C++11 提供的正则表达式库操作 `std::string` 对象,
9094

9195
int main() {
9296
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
93-
// 在 C++ 中 `\` 会被作为字符串内的转义符,为使 `\.` 作为正则表达式传递进去生效,需要对 `\` 进行二次转义,从而有 `\\.`
97+
// 在 C++ 中 \ 会被作为字符串内的转义符,为使 \. 作为正则表达式传递进去生效,需要对 \ 进行二次转义,从而有 \\.
9498
std::regex txt_regex("[a-z]+\\.txt");
9599
for (const auto &fname: fnames)
96100
std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
@@ -121,7 +125,7 @@ for(const auto &fname: fnames) {
121125
122126
以上两个代码段的输出结果为:
123127
124-
```
128+
```txt
125129
foo.txt: 1
126130
bar.txt: 1
127131
test: 0
@@ -133,7 +137,6 @@ sub-match[0]: bar.txt
133137
bar.txt sub-match[1]: bar
134138
```
135139

136-
137140
## 总结
138141

139142
本节简单介绍了正则表达式本身,然后根据使用正则表达式的主要需求,通过一个实际的例子介绍了正则表达式库的使用。
@@ -191,15 +194,15 @@ template<typename SERVER_TYPE>
191194
void start_server(SERVER_TYPE &server) {
192195
193196
// process GET request for /match/[digit+numbers], e.g. GET request is /match/abc123, will return abc123
194-
server.resource["^/match/([0-9a-zA-Z]+)/?$"]["GET"] = [](ostream& response, Request& request) {
197+
server.resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
195198
string number=request.path_match[1];
196199
response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length() << "\r\n\r\n" << number;
197200
};
198201
199202
// peocess default GET request; anonymous function will be called if no other matches
200203
// response files in folder web/
201204
// default: index.html
202-
server.default_resource["^/?(.*)$"]["GET"] = [](ostream& response, Request& request) {
205+
server.default_resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
203206
string filename = "www/";
204207
205208
string path = request.path_match[1];

pdf/en-us/modern-cpp-tutorial.pdf

29.2 KB
Binary file not shown.

pdf/zh-cn/modern-cpp-tutorial.pdf

13.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)