疯狂的石头

  • 首页

  • 归档

  • 分类

正则表达式元字符

发表于 2018-05-21 | 更新于 2018-09-10 | 分类于 随笔
元字符 注解
行定位点:"^"和"$" 这两个字符分别代表一行文字的开始和结束。例如,^mike将只会寻找以mike开始的行,同样mike$将只会寻找以mike结尾的行。
字符分类:"[]" 一对方括号被称为字符分类,你可以用来匹配任何一个和多个字符。假设你想匹配单词"gray",同时也想找一下被拼写成"grey"的单词。使用一个字符分类将允许你匹配这两者——正则表达式gr[ea]y被解读成匹配这样的字符串,一个g,一个r,跟着或者是一个e或者是一个a,跟着时一个y。字符分类中的^表示否定。
字符分类中的元字符:"-" 字符分类中的元字符"-"(dash)用来指出一个字符范围。字符分类[0123456789abcdefABCDEF]采用’-‘的话可以写成这样[0-9a-fA-F]。"-"只有在字符分类中才被认为是元字符。
选择性元字符:| | (pipe)意思是"or"。它允许你把多个表达式合成一个表达式,然后匹配里面任何单个表达式的结果,这些子表达式被称为备选项。例如,Mike和Mickael是两个独立的表达式,但是Mike
匹配可选项:"?" "?"(question mark)意味着可选。它放在正则表达式的某个字符的后面,这个字符允许在匹配结果中出现,也可以不出现。
数量符号:"+"、"*" 像"?"元字符一样,"+"(plus)和 "*"(star)元字符影响前导字符,可以匹配字符串中字符出现的数量("?"相当于0或者1次;"+"匹配一次或者多次;"*"表示匹配任何次)。
数量范围:"{}" "{最小, 最大}"表示指定的特定项目可以被匹配的最少和最大次数。
转义字符:"\" "\"(backslash)被用来转换指定元字符的含义,以便于把它们当成普通的字符来匹配。
圆括号:"()" 大部分正则表达式工具允许你用圆括号设定一个特定的表达式子集。
句点:"." "."(adot或point)是一种匹配任何字符的写法,在字符分类中"."就不是元字符了。
匹配边界:"\b" 匹配一个单词边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“remember”中的“er”,但不能匹配“pert”中的“er”。
匹配非边界:"\B" 匹配非单词边界。“er\B”能匹配“pert”中的“er”,但不能匹配“remember”中的“er”。
匹配数字字符:"\d" 匹配一个数字字符。等价于[0-9]。
匹配非数字字符:"\D" 匹配一个非数字字符。等价于[^0-9]。
匹配换页符:"\f" 匹配一个换页符。
匹配换行:"\n" 匹配一个换行符。
匹配换页符:"\r" 匹配一个换回车符。
匹配不可见字符:"\s" 匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
匹配任何可见字符:"\S" 匹配任何可见字符。等价于[^ \f\n\r\t\v]
匹配字母、数字、下划线:"\w" 匹配字母、数字、下划线。等价于[A-Za-z0-9_]
匹配非字母、数字、下划线:"\W" 匹配非字母、数字、下划线。等价于[^A-Za-z0-9_]

集合的实现

发表于 2018-05-21 | 更新于 2018-06-09 | 分类于 算法

由一个或多个确定的元素所构成的整体叫做集合。若x是集合A的元素,则记作x∈A。

集合中的元素有三个特征:

  1. 确定性(集合中的元素必须是确定的)。
  2. 互异性(集合中的元素互不相同)。例如:集合 A={1,a},则 a 不能等于 1。
  3. 无序性(集合中的元素没有先后之分),如集合 {3, 4, 5} 和 {3, 5, 4} 算作同一个集合。
阅读全文 »

JavaScript 处理异步的几种方法

发表于 2017-11-03 | 分类于 JavaScript

Javascript语言的执行环境是”单线程”(single thread)。为了解决由于执行耗时任务导致整个页面的卡顿的问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

1
2
3
4
// 可能会涉及到跨域请求的问题,tornado 解决方案:
// CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)
// 后面的*可以换成ip地址,意为允许访问的地址
self.set_header('Access-Control-Allow-Origin', '*')

async/await

虽然 co 是社区里面的优秀异步解决方案,但是并不是语言标准,只是一个过渡方案。ES7语言层面提供 async/await 去解决语言层面的难题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const request = require('request');

const options = {
url: 'https://localhost:9997/',
headers: {
'User-Agent': 'request'
}
};

const getRepoData = () => {
return new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (err) {
reject(err);
}
resolve(body);
});
});
};

async function asyncFun() {
try {
const value = await getRepoData();
// ... 和上面的yield类似,如果有多个异步流程,可以放在这里,比如
// const r1 = await getR1();
// const r2 = await getR2();
// const r3 = await getR3();
// 每个await相当于暂停,执行await之后会等待它后面的函数
//(不是generator)返回值之后再执行后面其它的 await 逻辑。
return value;
} catch (err) {
console.log(err);
}
}

asyncFun().then(x => console.log(`x: ${x}`)).catch(err => console.error(err));

tips:

  • async 用来申明里面包裹的内容可以进行同步的方式执行,await则是进行执行顺序控制,每次执行一个 await,程序都会暂停等待 await 返回值,然后再执行之后的 await。
  • await 后面调用的函数需要返回一个 promise,另外这个函数是一个普通的函数即可,而不是 generator。
  • await 只能用在 async 函数之中,用在普通函数中会报错。
  • await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try…catch 代码块中。

其实,async/await 的用法和 co 差不多,await 和 yield 都是表示暂停,外面包裹一层 async 或者 co 来表示里面的代码可以采用同步的方式进行处理。不过 async/await 里面的await 后面跟着的函数不需要额外处理,co 是需要将它写成一个 generator 的。

Promise

使用 Promise 可以很好的减少嵌套的层数,Promise 的实现采用了状态机,在函数里面可以很好的通过 resolve 和 reject 进行流程控制,可以按照顺序链式的去执行一系列代码逻辑。下面是使用 Promise 的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const request = require('request');
// 请求的url和header
const options = {
url: 'https://localhost:9997/',
headers: {
'User-Agent': 'request'
}
};

// 获取信息
const getRepoData = () => {
return new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (err) {
reject(err);
}
resolve(body);
});
});
};

getRepoData()
.then((result) => console.log(result))
.catch((reason) => console.error(reason));

// 此处如果是多个 Promise 顺序执行的话,如下:
// 每个 then 里面去执行下一个 promise
// getRepoData()
// .then((value2) => {return promise2})
// .then((value3) => {return promise3})
// .then((x) => console.log(x))

不过 Promise 仍然存在缺陷,它只是减少了嵌套,并不能完全消除嵌套。举个例子,对于多个 promise 串行执行的情况,第一个 promise 的逻辑执行完之后,我们需要在它的 then 函数里面去执行第二个 promise,这个时候会产生一层嵌套。

Generator

在 Node.js 中经常用的 tj/co 就是使用 generator 结合 promise 来实现的,co 是 coroutine 的简称,借鉴于 python、lua 等语言中的协程。它可以将异步的代码逻辑写成同步的方式,这使得代码的阅读和组织变得更加清晰,也便于调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const co = require('co');
const request = require('request');

const options = {
url: 'https://localhost:9997/',
headers: {
'User-Agent': 'request'
}
};
// yield 后面是一个生成器 generator
const getRepoData = function* () {
return new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (err) {
reject(err);
}
resolve(body);
});
});
};

co(function* () {
const result = yield getRepoData;
// ... 如果有多个异步流程,可以放在这里,比如
// const r1 = yield getR1;
// const r2 = yield getR2;
// const r3 = yield getR3;
// 每个yield相当于暂停,执行yield之后会等待它后面的 generator
// 返回值之后再执行后面其它的yield逻辑。
return result;
}).then(function (value) {
console.log(value);
}, function (err) {
console.error(err);

回调函数

这是异步编程最基本的方法。假定有两个函数fa和fb,后者等待前者的执行结果。如果fa是一个很耗时的任务,可以考虑改写fa,把fb写成fa的回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 改写前
fa();
fb();

// 改写后
function fa(callback) {
setTimeout(function() {
// fa 的任务代码
callback;
}, 1000);
}

// 执行改写后的代码
fa(fb);

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function a() {
  setTimeout(function() {
    console.log("setTimeout");
  }, 7000);
  
  function oneSecond() {
    var now = new Date();
    var exitTime = now.getTime() + 1000;
    while (true) {
      now = new Date();
      if (now.getTime() >= exitTime) {
        console.log("oneSecond");
        return;
      }
    }
  }
  oneSecond();
  function twoSecond() {
    var now = new Date();
    var exitTime = now.getTime() + 2000;
    while (true) {
      now = new Date();
      if (now.getTime() >= exitTime) {
        console.log("twoSecond");
        return;
      }
    }
  }
  twoSecond();
  function threeSecond() {
    var now = new Date();
    var exitTime = now.getTime() + 3000;
    while (true) {
      now = new Date();
      if (now.getTime() >= exitTime) {
        console.log("threeSecond");
        return;
      }
    }
  }
  threeSecond();
}

a();
console.log("Continue...");

执行结果:

1
2
3
4
5
6
7
oneSecond
twoSecond
threeSecond
Continue...
// 1(7-3-2-1)秒后输出 setTimeout,如果 setTimeout 小于7秒,
// 立即输出,但是顺序不变
setTimeout

Redux & React-redux

发表于 2017-09-07 | 分类于 随笔

Redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。它由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂性。

应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers。reducer 只是一个接收 state 和 action,并返回新的 state 的函数。 对于大的应用来说,不大可能仅仅只写一个这样的函数,所以我们编写很多小函数来分别管理 state 的一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function visibilityFilter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_VISIBILITY_FILTER') {
return action.filter;
} else {
return state;
}
}

function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }]);
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index ?
{ text: todo.text, completed: !todo.completed } :
todo
)
default:
return state;
}
}

再开发一个 reducer 调用这两个 reducer,进而来管理整个应用的 state:

1
2
3
4
5
6
function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
};
}

在vue中,可以使用vuex进行数据管理,在react中,可以使用redux进行数据管理。redux主要由Store、Reducer和Action组成:

  • Store:状态载体,访问状态、提交状态、监听状态变更
  • Reducer:状态更新具体执行者,纯函数(接收 state 和 action,并返回新的 state)
  • Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作

官方示例

React-redux

Redux 的 React 绑定库是基于容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)相分离的开发思想。

所有容器组件都可以访问 Redux store,所以可以手动监听它。一种方式是把它以 props 的形式传入到所有容器组件中。但这太麻烦了,因为必须要用 store 把展示组件包裹一层,仅仅是因为恰好在组件树中渲染了一个容器组件。

建议的方式是使用指定的 React Redux 组件 来让所有容器组件都可以访问 store,而不必显式地传递它。只需要在渲染根组件时使用即可。还有一个就是

1
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

连接 React 组件与 Redux store。

连接操作不会改变原来的组件类。

反而返回一个新的已与 Redux store 连接的组件类。

这种随处都可以使用、修改Redux中的数据的方式确实很方便,但Redux推荐的最佳实践还是在尽可能少的地方使用connect,把逻辑,数据相关的都放到容器组件中去处理,其他的组件都由容器组件所生成的props一层层传递下去然后渲染。

参考文档

进程、线程、协程

发表于 2017-05-19 | 更新于 2019-01-03 | 分类于 随笔

前言

内核

内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。

现代操作系统设计中,为减少系统本身的开销,往往将一些与硬件紧密相关的(如中断处理程序、设备驱动程序等)、基本的、公共的、运行频率较高的模块(如时钟管理、进程调度等)以及关键性数据结构独立开来,使之常驻内存,并对他们进行保护。通常把这一部分称之为操作系统的内核。

select、poll 和 epoll

阅读全文 »
1…789
Crazy Stone

Crazy Stone

step by step...

42 日志
9 分类
E-Mail GitHub
© 2018 — 2020 Crazy Stone
由 Hexo 强力驱动
|
主题 — NexT.Pisces