对应书中第8章 算法,这一章作者介绍的很简单,只是举例使用 foreach , minmax ,其他算法都略去了。
将C++的语法扩充,使用 foreach 循环变量。
需包含头文件
#include <boost/foreach_hpp>
具体用法:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
using namespace boost::assign;
vector<int> v = (list_of<int>(1),2,3,4,5);
/**
* 第一个参数 VAR 是循环变量声明 想要高效地使用序列内元素或者修改序列,需要声明使用引用
* 第二个参数 COL 是要遍历的序列
*
*/
BOOST_FOREACH(int x, v){
cout << x << "-";
}
cout << endl;
string str("hello world");
BOOST_FOREACH(char& c, str){
cout << c << "-";
}
cout << endl;
// use typeof
BOOST_TYPEOF(*v.begin()) y; // BOOST_AUTO(y, *v.begin())
BOOST_FOREACH(y, v){
cout << y << ",";
}
cout << endl;
return 0;
}
在同一次操作中同时获取最大最小值。需包含头文件:
#include <boost/algorithm/minmax.hpp>
using namespace boost;
具体用法:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/algorithm/minmax_element.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
using namespace boost::assign;
vector<int> v = (list_of(543), 90, 23, 42, 3, 10);
BOOST_AUTO(x ,boost::minmax_element(v.begin(), v.end()));
cout << "min: " << *x.first << endl;
cout << "max: " << *x.second << endl;
// first_min_element 找到第一个最小值
// last_min_element 最后一个最小值
return 0;
}
上一篇文章boost容器中留下一个property_tree
没有学,觉得既然 boost 提供了 property_tree 这样好的工具来给C++ 解析xml和Json,必须要留有一定的篇幅来讲它。
原先项目中使用到JSON,需要使用C++解析一段返回值, JSON 格式如下:
{
"ret": "101",
"error": [
{
"errortype": "A0001",
"errorstroke": {
"0": "0.2",
"1": "0.3"
}
},
{
"errortype": "A0021",
"errorstroke": {
"0": "0.2",
"1": "0.3"
}
}
]
}
error 字段是一个数组,数组中的每个元素都是一个对象Object,每个Object中是一个键值对,其中 errorstroke 同样包含一个对象。我们都知道JSON只包含三种数据结构,矢量,数组和映射(参考),这样无疑给我们的解析工作带来很多遍历,这三种数据结构几乎可以将时间所有的信息包含进去。
下面就是解析这段 JSON 字符串的具体代码:(注意将JSON字符串 escape)
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
using namespace boost::property_tree;
int main(int argc, const char * argv[]) {
std::string str_json = "{\"ret\":\"101\",\"error\":[{\"errortype\":\"A0001\",\"errorstroke\":{\"0\":\"0.2\",\"1\":\"0.3\"}},{\"errortype\":\"A0021\",\"errorstroke\":{\"0\":\"0.2\",\"1\":\"0.3\"}}]}";
ptree pt; //define property_tree object
std::stringstream ss(str_json);
try {
read_json(ss, pt); //parse json
} catch (ptree_error & e) {
return 1;
}
std::cout << pt.get<std::string>("ret") << std::endl;
ptree errortype = pt.get_child("error"); // get_child to get errors
// first way
for (boost::property_tree::ptree::iterator it = errortype.begin(); it != errortype.end(); ++it) {
std::cout << it->first;
std::cout << it->second.get<std::string>("errortype") << std::endl;
ptree errorstroke = it->second.get_child("errorstroke");
for (ptree::iterator iter = errorstroke.begin(); iter != errorstroke.end(); ++iter) {
std::string key = iter->first;
std::cout << iter->first << std::endl;
std::cout << iter->second.data() << std::endl;
}
}
// second way: using boost foreach feature
// BOOST_FOREACH(ptree::value_type &v, errortype){
// ptree& childparse = v.second;
// std::cout << childparse.get<std::string>("errortype") << std::endl;
// ptree errorstroke = childparse.get_child("errorstroke");
// BOOST_FOREACH(ptree::value_type& w, errorstroke){
// std::cout << w.first << std::endl;
// std::cout << w.second.data() << std::endl;
// }
// }
return 0;
}
代码的输出:
101
A0001
0
0.2
1
0.3
A0021
0
0.2
1
0.3
再换用另外一段 JSON 尝试解析,从下面这段 JSON 中能够轻易的看出 JSON 内部的结构,支持的数据结构和类型:
{
"array": [
1,
2,
3
],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}
具体解析代码:
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
using namespace std;
using namespace boost::property_tree;
int main(int argc, const char * argv[]) {
std::string str_json = "{\"array\":[1,2,3],\"boolean\":true,\"null\":null,\"number\":123,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"string\":\"Hello World\"}";
ptree pt; //define property_tree object
std::stringstream ss(str_json);
try {
read_json(ss, pt); //parse json
} catch (ptree_error & e) {
return 1;
}
ptree arraypt =pt.get_child("array");
for (boost::property_tree::ptree::iterator it = arraypt.begin(); it != arraypt.end(); ++it) {
cout << it->second.data() << " ";
}
cout << endl;
std::cout << pt.get<bool>("boolean") << std::endl;
std::cout << pt.get<std::string>("null") << std::endl;
std::cout << pt.get<int>("number") << std::endl;
std::cout << pt.get<std::string>("string") << std::endl;
ptree opt = pt.get_child("object");
BOOST_FOREACH(ptree::value_type &v, opt){
cout << v.first << " : ";
cout << v.second.data() << endl;
}
return 0;
}
利用 Boost property_tree 构造 JSON 字串,以下代码能够构造上面的JSON:
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
using namespace std;
using namespace boost::property_tree;
int main(int argc, const char * argv[]) {
std::string str_json = "{\"array\":[1,2,3],\"boolean\":true,\"null\":null,\"number\":123,\"object\":{\"a\":\"b\",\"c\":\"d\",\"e\":\"f\"},\"string\":\"Hello World\"}";
ptree root, arr,object;
arr.push_back(std::make_pair("","1"));
arr.push_back(std::make_pair("","2"));
arr.push_back(std::make_pair("","3"));
object.put("a","b");
object.put("c","d");
object.put("e","f");
root.add_child("array", arr);
bool boolvalue = true;
root.put("boolean",boolvalue);
root.put("null","null");
int num = 123;
root.put("number",num);
root.add_child("object",object);
root.put("string","Hello World");
//write_json("out.json", root);
stringstream s;
write_json(s, root, false);
string out = s.str();
cout << out ;
return 0;
}
两个有用的JSON工具:
Boost property_tree 解析 XML 可参考这篇文章 ,解释得非常清楚。
APT 是 Advanced Packaging Tools 的缩写,是 Debian 及其派生的发行版(使用最广泛的 Ubuntu/Linux Mint 等等)的软件包管理器。 APT 可以自动下载、配置和安装二进制或源代码格式软件包,简化了 Unix 系统上管理软件的过程。 APT 最早被设计成 dpkg 的前端,用来处理 deb 格式的软件包。
APT 主要由以下几个命令组成:
apt-get
apt-cache
apt-file
APT 能够自动处理软件的依赖问题,大大简化了工作流程
这里主要讲 apt-get
的常见用法
apt search package_name
apt install package
自动根据 /etc/apt/sources.list
中的设定,以及 /etc/apt/sources.list.d
目录下的设定,更新软件资料源。
sudo apt update
使用如下命令安装更新
sudo apt upgrade
apt remove package # 移除软件包,但是保留配置文件
apt purge package #移除软件包并移除配置
apt autoremove # 移除孤立的并不被依赖的软件包
apt list
sudo apt-get dist-upgrade
最后如果还有什么不明了的,可以 man apk
。
我目前使用
对应书中的第七章容器与数据结构。先是讲了五个容器: array , dynamic_bitset, unordered, bimap和 circular_buffer. 他们都是对标准容器的扩充。
tuple, any 和 variant 能够容纳不同类型容器
最后 multi_array
和 property_tree
两个组件使用组合模式实现复杂的数据结构。 multi_array
是一个泛型多维容器, property_tree
出自 1.41 版,可以解析 xml, son, ini 和 info 四种格式文件,在内部构造属性树。
对容纳元素基本要求:析构函数不能抛出异常
数组容器,包装了 C++ 内建数组,为其提供标准 STL 容器接口,begin(), front() 等等,性能与原始数组相差不大。但是 array 功能有限,当需要可变容量数组时,还是需要借助 std::vector 或者 boost::scoped_array
array 主要缺陷:
需包含头文件
#include <boost/array.hpp>
using namespace boost;
具体用法:
#include <iostream>
#include <boost/array.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
int main(int argc, const char * argv[]) {
// 赋值
array<int, 5> myArray;
myArray[1] = 2;
myArray.front() = 1;
myArray.back() = 5;
// 获取指针
int* p = myArray.c_array();
*(p+2) = 3;
for (array<int,5>::iterator itr = myArray.begin(); itr != myArray.end(); ++itr) {
std::cout << *itr << std::endl;
}
array<int, 10> arr2;
arr2.assign(5);
for (BOOST_AUTO(pos, arr2.begin()); pos != arr2.end(); ++pos) {
std::cout << *pos << ",";
}
// 类似数组的初始化
array<int, 3> ar3= { 1, 2, 3 };
array<int, 10> ar4 = {0}; // all element equal 0
array<std::string, 5> ar5= {"first"}; // 初始化第一个元素
return 0;
}
C++98 标准为处理二进制提供了两个工具: vector
需包含如下头文件
#include <boost/dynamic_bitset.hpp>
using namespace boost;
unordered 库提供两个散列集合类 unordered_set
和 unordered_multiset
,同样 STLport 库也提供 hash_set 和 hash_multiset. 他们接口、用法和 STL 中标准关联容器 set/multiset 相同,只是内部使用散列代替二叉树实现,因此查找复杂度由对数降为常数。
散列容器 hash container 比二叉树的存储方式可以提供更高的访问效率。boost.unordered 库提供了一个完全符合 C++ 新标准草案 TR1 的散列容器实现,包括无序集合 set 和 无序映射 map.
unordered 库提供两个散列映射类 unordered_map
和 unordered_multimap
,同样 STLport 中也提供了 hash_map/hash_multimap. 他们的接口、用法和 STL 中的标准关联容器 map/multimap 相同,只是内部使用散列表代替了二叉树。
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;
代码:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
// 散列集合类
using namespace boost::assign;
using namespace boost::unordered;
// 散列集合
unordered_set<string> s = (list_of<string>("one")("two")("three"));
s.insert("four");
s.erase("two");
unordered_set<string>::iterator it = s.find("one");
s.erase(it);
for (unordered_set<string>::iterator itr = s.begin(); itr != s.end(); ++itr) {
cout << *itr << endl;
}
s.empty();
// 关联式容器
unordered_map<int, std::string> um = map_list_of(1,"one")(2,"two")(3,"three");
um.insert(std::make_pair(10,"ten"));
um[11] = "eleven";
um[15] = "fifteen";
std::cout << um[15] << std::endl;
BOOST_AUTO(p, um.begin());
for (p; p!= um.end(); ++p) {
cout << p->first << "-" << p->second << ",";
}
cout << endl;
um.erase(11); // delete key 11
cout << um.size() << endl;
// stl map
map<int, std::string> stdmap;
// assignment
stdmap.insert(map<int, std::string>::value_type(1, "one"));
stdmap.insert(std::pair<int, std::string>(2, "two"));
stdmap.insert(std::make_pair(3, "three"));
stdmap[4] = "four";
map<int, std::string>::iterator pos;
for (pos = stdmap.begin(); pos != stdmap.end(); ++pos) {
std::cout<< "key: " << pos->first << "\t"
<< "value: " << pos->second << "\n";
}
stdmap.erase(4);
cout << "map size " << stdmap.size() << endl;
return 0;
}
可以容纳两个类型的元素,类似于 C++标准提供的映射型容器 map 和 multi_map ,但是 C++标准中的关联数组,只是将一个 key 映射到一个 value, 这种关系是单向的,只能从 key 到 value 而不能反过来。因此 boost.bimap 扩展了标准库的映射型容器,提供双向映射的能力。
对于 bimap<X, Y>
, bimap.let 相当于 map<X, Y>
,而 bimap.right 相当于 map<Y, X>
bimap<collection_type_of<X>, collection_type_of<Y> >
这个概念下, std::map 和 std::multi_map 的左值是一个有序的集合,而右组无任何约束,对应的 bimap 是:
bimap< set_of<X> , unconstrained_set_of<Y> > 和 bimap<multiset_of<X>, unconstrained_set_of<Y> >
bimap 定义的集合类型包括如下:
bimap 可以使用 using namespace tags;
tagged类给左组和右组数据在语法层面加上“标签”。标签的定义如下:
template< class Type, class Tag>
struct tagged {
typedef Type value_type;
typedef Tag tag;
};
tagged<int , struct id> 表示包装了 int 类型 ,标签名字是 id.
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/vector_of.hpp>
#include <boost/bimap/unconstrained_set_of.hpp>
#include <boost/assign.hpp>
using namespace boost;
using namespace std;
template< typename T>
void print_map(T& m){
for (BOOST_AUTO(pos, m.begin()); pos != m.end(); ++pos) {
cout << pos->first << "<-->" << pos->second << endl;
}
}
int main(int argc, const char * argv[]) {
using namespace boost::bimaps;
using namespace tags;
// bimap
bimap<int, string> bmap;
bmap.left.insert(make_pair(1, "one"));
bmap.right.insert(make_pair("two", 2));
for (BOOST_AUTO(pos, bmap.left.begin()); pos != bmap.left.end(); ++pos) {
cout << "left key: " << pos->first << " value: " << pos->second << endl;
}
// 类型集合位于名字空间 boost::bimaps, 需包含各自同名头文件,文件位于 <boost/bimap/list_of.hpp>
// 左组是有序集合,右组是无序集合
bimap<int, unordered_set_of< string > > bm1;
// 左组和右组都是有序多值集合
bimap< multiset_of<int> , multiset_of< string > > bm2;
// 左组是无序集合,右组是一个序列,只能有左视图
bimap< unordered_set_of<int> , list_of<string> > bm3;
// 左组随机访问集合,右组无约束
bimap< vector_of<int>, unconstrained_set_of< string > > bm4;
bimap<tagged<int, struct id>, tagged<string, struct name> > bm;
bm.by<id>().insert(make_pair(1, "Sam"));
bm.by<name>().insert(make_pair("Tom", 2));
print_map(bm.by<id>());
typedef bimap<int, string> bm_t;
using namespace boost::assign;
bm_t bmt = assign::list_of<bm_t::relation>(1, "one")(2 , "two");
BOOST_AUTO(pos, bmt.left.find(2));
cout << "key: " << pos->first << "\t" << "value: "<< pos->second << endl;
BOOST_AUTO(pos2, bmt.right.find("one"));
cout << "key: " << pos2->first << "\t" << "value: " << pos2->second << endl;
bmt.left.replace_key(pos, 22);
bmt.left.replace_data(pos, "replaced two");
print_map(bmt.left);
return 0;
}
bimap 还有很多高级用法,等用到的时候查阅文档吧。
循环缓冲区数据结构,大小固定的循环队列。固定大小的缓存容量,当新增加的元素超过缓冲区的容量时,自动将最初的元素覆盖。
tuple 元组 定义了固定数目元素的容器,其中每个元素类型都可以不相同,这与其他容器有本质的区别。
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/tuple/tuple_io.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
typedef boost::tuple<int, string, double> my_tuple;
my_tuple tuple0(1,"test");
my_tuple tuple1 = tuple0;
my_tuple tuple2;
tuple2 = tuple0;
my_tuple t1 = boost::make_tuple(2,"test",100.0);
assert(t1.get<0>() == 2);
assert(t1.get<1>() == "test");
// 比较
my_tuple t2 = boost::make_tuple(3,"test",200.00);
assert(t1 < t2);
// io
cout << t1 << endl;
cout << "input tuple: example: (1 test 200.0)"<<endl;
cin >> t1;
cout << t1 << endl;
using namespace boost::assign;
vector<my_tuple> v = tuple_list_of(1, "1", 1.0)(2, "2", 2.0);
assert(v.size() == 2);
return 0;
}
特殊容器,只能容纳一个元素,但这个元素可以是任意类型—— int , double, string, STL 容器或者任意自定义类型。程序可以用 any 保存任意的数据,在任何需要的时候将它取出来,这种功能与 shared_ptr<void>
有些类似,但 any 是类型安全的。 any 不是一个模板类。
不要用 any 保存原始指针,代替用 shared_ptr 智能指针。
当 any 以指针的方式传入 any_cast() 的时候,返回的指针类型与传入的 any 对象具有相同的常量。如果 any 不持有任何对象,这两个 any_cast() 不会抛出异常,而是返回一个空指针。
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/any.hpp>
using namespace boost;
using namespace std;
// check object type in any
template< typename T>
bool can_cast(any &a){
return typeid(T) == a.type();
}
// get value in any
template< typename T>
T& get(any &a){ // & 不能丢失,否则无法修改 a 的值
BOOST_ASSERT(can_cast<T>(a));
return *any_cast<T>(&a);
}
template< typename T>
T* get_pointer(any &a){
BOOST_ASSERT(can_cast<T>(a));
return any_cast<T>(&a);
}
int main(int argc, const char * argv[]) {
any a(10);
int n = any_cast<int>(a); // get value return a copy of a's data : 10
// any_cast<double>(a) throw bad_any_cast
assert(n == 10);
a = string("test");
a = vector<vector<int> >();
a = n;
assert(can_cast<int>(a));
get<int>(a) = 11; // Will change a value this line
*get_pointer<int>(a) = 12;
return 0;
}
与 any 类似,是可变类型,对 C++中 union 概念增强和扩展。
需要头文件:
#include <boost/variant.hpp>
using namespace boost;
例子:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/variant.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
typedef variant<int, double, string> var_t;
var_t v; // v == 0
assert(v.type() == typeid(int));
assert(v.which() == 0);
v = "test string"; // v -> string
cout << *get<string>(&v) << endl; // get()
try {
cout << get<double>(v) << endl;
} catch (bad_get &) {
cout << "bad_get" << endl;
}
return 0;
}
variant 和 any 都可以保存多类型的变量,但是他们的使用是有区别的。
多维数组 的高效实现。 multi_array 是递归定义的。
#include <boost/multi_array.hpp>
using namespace boost;
具体用法:
#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/array.hpp>
#include <boost/multi_array.hpp>
#include <boost/multi_array/extent_gen.hpp>
using namespace boost;
using namespace std;
int main(int argc, const char * argv[]) {
multi_array<int, 3> ma; // 定义三维数组
multi_array<int, 3> ma1(extents[2][3][4]); // 定义维度 2/ 3/ 4 的三维数组
for (int i=0 , v= 0; i < 2; ++i) {
for (int j =0 ; j< 3; ++j) {
for (int k = 0; k < 4; ++k) {
ma1[i][j][k] = v++;
}
}
}
boost::array<size_t, 3> idx = { 0,1,2};
ma1(idx) = 10;
cout << ma1(idx) << endl;
boost::array<size_t, 3> arr = { 4,3,2};
ma1.reshape(arr);
for (int i = 0; i< ma1.shape()[0]; ++i) {
for (int j = 0 ; j < ma1.shape()[1]; ++j) {
for (int k = 0 ; k < ma1.shape()[2]; ++k) {
cout << ma1[i][j][k] << ",";
}
}
}
ma1.resize(extents[2][9][9]); // 改变多维数组的大小
// 创建子视图
/**
* (0, 1, 2, 3)
* (4, 5, 6, 7)
* (8, 9, 10, 11)
*/
typedef multi_array<int, 2> ma_type;
multi_array<int, 2> mademo(extents[3][4]);
for (int i = 0, v = 0; i< mademo.shape()[0]; ++i) {
for (int j = 0 ; j < mademo.shape()[1]; ++j) {
mademo[i][j] = v++;
}
}
cout << endl;
typedef ma_type::index_range range;
indices[range(0,2)][range(0,2)];
/**
* (0, 1)
* (4, 5)
*/
BOOST_AUTO(view, mademo[indices[range(0,2)][range(0,2)] ]);
// ma_type::array_view<2>::type view = ma[indices[range(0,2)[range(0,2)]];
cout << view.num_dimensions() << endl;
// 将一维数组适配成多维数组
// 提供了 multi_array_ref 和 const_multi_array_ref
// 适配完不能动态增长,其他和 multi_array 完全相同
// const_multi_array_ref 功能少一些,因为它是只读的
int arra[12];
for (int i = 0; i < 12; ++i) {
arra[i] = i;
}
multi_array_ref<int, 2> mar(arra, extents[3][4]);
const_multi_array_ref<int, 2> cmar(arra, extents[2][6]);
return 0;
}
property_tree 容器比较复杂,它是一个保存了多个属性值得树形数据结构,功能强大,可以解析 xml, ini, json 和 info 四种格式的文本数据。单独拿一篇文章来讲它好了。
我果然不是星战迷,也没有星战情怀,相比同档期电影可以一看,但是我不是很喜欢这一部。 剧情6分(标准套路,困境解决困境),表演6.5(黑人演员可圈可点,女主没什么说的,机器人没有语言没有表情却异常的生动),娱乐性8分(一分光剑一分BB8)。
星战前六部,正传三部,前传三部,稍早的时候看过了,看原力觉醒之前没有认真补课。但是我知道好莱坞成熟流水线上的电影是不会要求你必须看完前六部再来看这一部电影的,每一部完整的电影都会有其完整的剧情和完整的人物描述。回到这一部原力觉醒,可能是星战迷内心的浴火被燃烧了,从第一部到今年三四十年的时间,足够让一个从青年变成中年甚至老年,伴随星战迷成长的电影总会伴随这一系列的讨论,今天早上看票房成绩已经是影史第四,超过票房第一的阿凡达已经是板上钉钉。基于这样的环境去影院看了。
就像之前说过的那样,这一部在剧情上的设定就是好莱坞标准的剧本设定,产生新的反派,然后需要正义人士组织反抗,制定计划一步一步瓦解反派,实在没有任何需要交代的内容。我甚至在观影过程中连续两次打哈欠,这实属罕见,在以前从来没有出现过,甚至在看《刺客聂隐娘》在场有人睡着的情况下我也没有困意,而这一部看到女主发觉拥有原力,Resistance组织开始制定作战计划开始就已经注定了结局。再到爱情,亲情的设定,总觉得会产生一些问题,大战刚刚结束,公主与将军的见面,再到后面父子的见面总感觉设定上有一些故意而为之。当然这些都是一些小的问题,总体来看剧情还是有一个及格的6分。至少前半部分,已经后面的一些情节,总能够让观众一边被主人公的台词表演逗笑,一边被剧情的紧张气氛而胆战心惊。
再到表演,其实也并没有什么说得,反而到时那个萌萌的机器人能让观众会心一笑,有些时候表演并不需要语言和表情,一举一动都能够看出表演的出彩,或许这也是这部电影在表演上能给我留下的唯一印象,女主,黑人男主,再到哈里森福特,并没有什么特别出彩的地方。
观影风向标定下的娱乐性,其实一直不大明白,娱乐到底是指那一方面,如果是指话题性,新闻性,亦或是卖萌属性的话,就像上面说得那样我会一分给光剑,这一分给的是情怀,一分给BB8,那是因为这个“球”真是太可爱了,可爱到人人都会想要拥有一台。
总之这是一部让我觉得值得票价却也提不出什么优点的电影啦。感谢导演 JJ 艾布拉姆斯,感谢哈里森福特。
Guake is a drop-down terminal for the GNOME desktop which includes split terminal functionality, session save/restore, support for transparency, and many other features.
配置 zsh guake 小记
sudo apt-get update && sudo apt-get install zsh
wget –no-check-certificate https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O – | sh
chsh -s $(which zsh)
From here: https://github.com/robbyrussell/oh-my-zsh
Edit zshrc config vim ~/.zshrc
ZSH_THEME="agnoster"
Install missing fonts here: https://github.com/Lokaltog/powerline-fonts After install missing font, change terminal font to “Melon xx”.
fc-cache -f -v
According to this: https://github.com/coolwanglu/guake-colors-solarized git clone
this repo and run ./set_dark solarized
.
Alt + T
for new tabAlt + W
for close current tabAlt + N
to go to previous tabAlt + P
to go to next tabAlt + C
for copy text to clipboardAlt + V
for paste text from clipboardGuake 自带的终端内搜索 Ctrl + Shift + F
And here is another article about guake, I am taking some shorcut configs from this article. And if you want to build guake from source, you can take a look at thie article.
And all the source code: https://github.com/Guake/guake.
字符串相关库,对应书中第五章 字符串与文本处理,大大增强了C++在文本处理上的能力。 lexical_cast 实现了字符串和数字之间的方便转换;format库提供了C++ 类似 printf() 的能力,用以格式化输出;string_algo 是一个算法库,提供了大量与字符串和文本处理相关的算法;tokenizer 库专注于文本处理领域的分词功能;xpressive 是一个灵活且功能强大的正则表达式解析库。
之前单独有一篇文章讲 lexical_cast 这里不再重复。
format 基本集成了 printf 的格式化语法,每个 printf 格式化选项都以 % 符号开始,后面是格式规则,例如
新增格式:
需要包含头文件
#include <boost/format.hpp>
using namespace boost;
例子:
cout << format ("%s:%d+%d=%d\n" )% "sum" % 1 % 2 % (1+2);
format fmt("(%1% + %2%) * %2% = %3%\n" );
fmt % 2 % 5 % ((2+5) * 5);
cout << fmt.str();
/**
* 程序结果
* sum:1+2=3
* (2 + 5) * 5 = 35
*/
format 还有很多高级的用法,参见文档。
C++98 标准库中提供了字符串标准类 std::string , 它有一些基本成员函数用以查询子串,访问字符,等基本功能。
提供全面的字符串算法库
包含头文件
#include <boost/algorithm/string.hpp>
using namespace boost;
例子:
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
int main() {
string str("readme.txt");
if (ends_with(str, " txt")) {
cout << to_upper_copy(str) + "UPPER" << endl; // upper case
}
replace_first(str, "readme ", "followme "); // replace
cout << str << endl;
vector<char> v(str.begin(), str.end());
vector<char> v2 = to_upper_copy(erase_first_copy(v, "txt ")); // delete sub string
for (int i = 0; i < v2.size(); ++i) {
cout << v2[i];
}
return 0;
}
string_algo 库命名遵循标准库惯例,算法名均为小写形式,并使用不同前缀或者后缀来区分不同版本,命名规则如下:
string_algo 库提供算法共分为五大类:
每一类算法中都会包含一系列函数。
tokenizer 库是专门用于分词 token 字符串处理库,可以用简单方法把一个字符串分解成若干单词。
tokenizer 库可以容易地执行分词操作,但是它存在一些固有的缺陷。
需包含头文件:
#include <boost/bokenizer.hpp>
using namespace boost;
例子:
#include <iostream>
#include <vector>
#include <cstring>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
template<typename T>
void print(T &tok) {
for (BOOST_AUTO(pos, tok.begin()); pos != tok.end(); ++pos) {
cout << *pos << "|\t";
}
cout << endl;
}
int main() {
string str("Link radfe the dfafe -adfead");
tokenizer<> tok(str);
print(tok);
/**
* char_separator
* 第一个参数 dropped_delims 分隔符集合,这个集合中的字符不会作为分词结果出现
* 第二个参数 kept_delims 分隔符集合,其中的字符会保留在分词结果中
* 第三个参数 empty_tokens 类似 split 算法 eCompress 参数,处理两个连续出现的分隔符。 keep_empty_tokens 表示连续出现的分隔符标识了一个空字符串。
* 使用默认构造函数,不传入任何参数,行为等同于 char_separator(" ",标点符号字符, drop_empty_tokens) ,以空格和标点符号分词,保留标点符号,不输出空白单词。
*/
char * s = "xxx ;; <yyy-zzz> !!!";
char_separator<char> sep;
tokenizer<char_separator<char>, char *> tok1(s, s + strlen(s), sep);
print(tok1);
char_separator<char> sep1(";-<>!", "", keep_empty_tokens);
tok1.assign(s, s + strlen(s), sep1);
print(tok1);
char_separator<char> sep2(" ;-!", "<>", drop_empty_tokens);
tok1.assign(s, s + strlen(s), sep2);
print(tok1);
/**
* escaped_list_separator
* 专门处理 CSV 格式(Comma Split Value,逗号分割值)的分词对象
* 第一个参数 e 指定了字符串中的转义字符,默认是斜杠\
* 第二个参数是分隔符,默认是逗号
* 第三个参数是引号字符,默认是"
*/
string strcom = "id,100,name,\" mario\"";
escaped_list_separator<char> sepcom;
tokenizer<escaped_list_separator<char> > tokcom(strcom, sepcom);
print(tokcom);
/**
* offset_separator
* 不是基于分隔符,而是使用偏移量,在处理某些不使用分隔符,而使用固定字段宽度文本时非常有用。
* 构造函数接受两个迭代器,也可以是数组指针begin end,指定分词用的整数偏移量序列,整个序列每个元素是分词的宽度
*
bool 参数 bwrapoffsets ,决定是否在偏移量用完之后继续分词
*
bool 参数 return_partial_last 决定在偏移量序列最后是否返回分词不足的部分
* 最后两个参数默认值都是true
*/
string stroffset = "2233344445566666666";
int offsets[] = { 2, 3, 4 };
offset_separator sepoff(offsets, offsets + 3, true, false);
tokenizer<offset_separator> tokoff(stroffset, sepoff);
print(tokoff);
offset_separator sepoff2(offsets, offsets + 3, false);
tokoff.assign(stroffset, sepoff2);
print(tokoff);
offset_separator sepoff3(offsets, offsets + 3, true, false);
print(tokoff);
return 0;
}
正则表达式是处理文本强有力的工具,使用复杂的语法规则,能够解决文本处理领域绝大多数问题,诸如验证、匹配、查找、替换等等。xpressive 是一个先进的、灵活的、功能强大的正则表达式库,提供了对正则表达式全面的支持,而且比原正则表达式库 boost.regex 要好的是它不需要编译,速度快,同时语法又很类似。
xpressive 提供动态和静态两种方式。静态方式使用操作符重载生成编译期的表达对象,可以在编译期进行正则表达式的语法检查。动态的方式则是较传统的用法,与 boost.regex 和 Python 中的 re 模块相似,以字符串作为一个表达式对象,在运行时进行语法检查和处理。
正则表达式定义了一套完善而复杂的语法规则,用于匹配特定模式的字符串,少量字符被用于定义特殊匹配模式语法,它们是: .^$()*+?{}[]\|。
其他经常使用 \d 匹配数字 [0-9] , \w 匹配字母 [a-z] , \s 匹配空格等。
C++ 代码中的斜杠需要变成双斜杠,在使用正则表达式时,在语句前使用注释保存原始表达式,以方便未来的调试和维护。
sregex
和 cregex
用于操作std::string ,和 C风格字符串。须有如下命名空间:
using namespace boost::xpressive;
例子:
#include <iostream>
#include <vector>
#include <cstring>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/tokenizer.hpp>
#include <boost/xpressive/xpressive_dynamic.hpp>
using namespace std;
using namespace boost;
int main() {
using namespace boost::xpressive;
string s = "Hi world, I am from Mars!";
sregex reg = sregex::compile("(M\\w{3})");
bool ret = regex_match(s, reg);
// match identity card number
// 18 number , first 6 area code, middle 8 birthday, last 4 random number possible x
// \d{6}(1|2)\d{3}(0|1)\d[0-3]\d\d{3}(X|\d)
// regex_search
// regex_search 检测输入表达式中是否包含正则表达式,即存在一个匹配正则表达式的子串
char* str = "there is a power-suit item";
cregex creg = cregex::compile("(power)-(.{4})\\s(\\w{4})", icase);
ret = regex_search(str, creg);
cmatch what;
regex_search(str , what, creg);
for (int i = 0; i < what.size() ; ++i){
cout << what[i] << endl;
}
// 替换
// regex_replace()
cout << regex_replace(s , reg , "Earth") << endl; // replace Mars with Earth
cout << regex_replace(s , reg , "$1 haha") << endl;
cout << regex_replace(s , reg , "$1 $&") << endl;
s = regex_replace(s , reg , "Earth");
cout << s << endl;
// regex_iterator<>
string ss = "boost1, Boost2, BoOst3, etc";
sregex ssreg = sregex::compile("boost\\d",icase);
sregex_iterator pos(ss.begin(), ss.end(), ssreg);
sregex_iterator end;
while(pos != end){
cout << (*pos)[0] << "\t";
++pos;
}
return 0;
}
如果要更加了解 JVM 启动参数,那么对 JVM 的内存结构需要有一定的了解。JVM 内存主要分为三大块:
初始堆大小,默认值是物理内存的 1/64 . 默认 (MinHeapFreeRatio 参数可以调整)空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制。
最大堆大小,物理内存的 1/4(小于 1GB), 默认 (MaxHeapFreeRatio 参数可以调整)空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制。
当堆内存空间溢出时输出堆的内存快照
通常配合 -XX:HeapDumpPath
使用,输出到文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/java_error_xxx.hprof
只有当发生 java.lang.OutOfMemo-ryError
时,才会 dump 到指定文件。
得到 hprof 文件后使用 memory analyzer tool(比如http://eclipse.org/mat/) 来分析。
设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM 会自动调整年轻代大小,以满足此值。
整个堆占用量,开始 GC 。 默认值为 45,当值为 0 时,表示 “do constant GC cycles”。
使用 Garbage First(G1) Collector.
JVM 人为设置了 stack trace 的限制为 1024,可以使用该参数来增加该限制。-1
值表示没有限制。
JVM 致命错误。
该文件包含如下几类关键信息:
查看系统版本和发行版的命令有很多,这里就列一些比较常见的。
uname -a
Linux ev 4.4.0-66-generic #87-Ubuntu SMP Fri Mar 3 15:29:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
uname -r
print distribution-specific information
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.1 LTS
Release: 16.04
Codename: xenial
inxi -S
用 Google 日历很多年,但却一直没有体会到 Google Calendar 的精髓,最近在使用过程中越来越得心应手,原因是结合手机的通知栏,能够非常方便的提醒日程。而 Google Calendar 在安排日程之外很棒的一点就是能够共享日历,不管是小到自己的行程安排,再到团队的时间规划安排,再大到一个国家的节假日都能非常轻松的分享出去。
早之前就已经添加了 中国的节假日日历,还有历史上的今天一些有趣的日历,这里就做个总结,在默认情况下 Google Calendar 在左边侧边会有一项 添加日历,在菜单中可以选择 “Browse calendars of interest” 然后在 Google 提供的清单中能够轻松的找到 “宗教日历”,包括 Christian,Jewish,Muslim,Orthodox 的日历,然后还有基于地区的日历,其中包括世界上很多国家的节假日日历,另外还有体育运动的日历,包括篮球、橄榄球、英式足球等各种赛事分类,甚至还有月相(Phases of the Moon) 的日历。简单的勾选即可添加到日历中。
比如说:
其实仔细观察一下就能发现这些日历的 ID,都是语言加上地区,比如说 zh-cn.china#holiday
,zh_cn.china#holiday
表示的就是中文显示中国的节假日,而 en.china#holiday
就表示英文显示中国的假日。
不得不说,其实已经不用添加农历日历了,Google Calendar 已经默认自带了农历,并且和整体搭配非常美观。在设置中,“视图选项”,其中有其他日历选项,选择中文简体,那么就会添加农历日历到界面中。
一个综合型日历分享网站