boost 学习笔记 9:并发编程

Boost中有两个用于并发编程的组件。首先是thead库:它为C++增加了可移植的线程处理能力。然后是一个用于同步和异步IO操作的功能强大的库——asio,它使用了前摄器模式,可以处理串口,网络通信,而且有望成为C++标准底层通信库。

互斥量是一种用于线程同步的手段,它可以在线程编程中防止多个线程同时操作共享资源(或称临界区)。一旦一个线程锁定了互斥量,那么其他线程必须等待他解锁互斥量才能在访问共享资源。thead提供了7中互斥量类型(实际只有五种):

  • mutex 独占式互斥量
  • try-mutex mutex 同义词
  • timed_mutex 独占式互斥量,提供超时锁定功能
  • recursive_mutex 递归式互斥量,可以多次锁定,相应也要多次解锁
  • recursive_try_mutex recursive_mutex 同义词
  • recursive_time_mutex 递归式互斥量,基本功能同 recursive_mutex ,提供超时锁定功能
  • shared_mutex multi-reader/single-writer 型共享互斥量 读写锁

mac下使用 boost thread 需要将 libboost_thread.dylib libboost_thread-mt.dylib lib boost-system.dylib 加入到工程,链接进工程。

具体用法:

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
using namespace boost;
using namespace std;

#define BOOST_DATE_TIME_SOURCE
#define BOOST_THREAD_NO_LIB

// 模板类配合模板参数提供不同范围的计数,提供隐式类型转换操作
// 在多线程环境下安全计数
template <typename T>
class basic_atom: noncopyable {
private:
    T n;
    typedef boost::mutex mutex_t;
    mutex_t mu;

public:
    basic_atom(T x = T()):n(x) {}
    T operator++(){
        mutex_t::scoped_lock lock(mu);
        return ++n;
    }
//    T operator=(const T _n){
//        mutex_t::scoped_lock lock(mu);
//        n = _n;
//        return _n;
//    }
    operator T()    {return n;}
};

boost::mutex io_mu;

typedef basic_atom<int> atom_int;

void printing(atom_int& x, const string& str){
    for (int i = 0;  i < 5; ++i) {
        boost::mutex::scoped_lock lock(io_mu);
        cout << str << ++x <<endl;
    }
}

void to_interrupt(atom_int& x, const string& str){
    try {
        for (int i = 0;  i < 5; ++i) {
            this_thread::sleep(posix_time::seconds(1));
            boost::mutex::scoped_lock lock(io_mu);
            cout << str << ++x <<endl;
        }
    } catch (thread_interrupted& ) {
        cout << "thread_interrupted" <<endl;
    }
}

int main(int argc, const char * argv[]) {

    cout << "start" <<endl;
    this_thread::sleep(posix_time::seconds(2));
    cout << "sleep 2 seconds" <<endl;

    boost::mutex mu;
    try {
        mu.lock();
        cout << "do some operations" << endl;
        mu.unlock();
    } catch (...) {
        mu.unlock();
    }

    boost::mutex mu1;
    boost::mutex::scoped_lock lock(mu1);
    cout << "some operations" <<endl;

    atom_int x;

    thread t1(printing, boost::ref(x), "hello");

//    this_thread::sleep(posix_time::seconds(2));

    // join & timed_join
    if (t1.joinable()) {
        t1.join();          // 等待t1 线程结束再返回,不管执行多长时间
    }

    thread t2(printing, boost::ref(x), "boost");
    t2.timed_join(posix_time::seconds(1));      // 最多等待1秒返回

    thread t(to_interrupt, boost::ref(x), "interrupt");
    this_thread::sleep(posix_time::seconds(4));
    t.interrupt();
    t.join();

    return 0;
}

asio

Boost.Asio是一个跨平台的、主要用于网络和其他一些底层输入/输出编程的C++库。以下代码实现一个简单的tcp服务,访问http://localhost:6688可得到字符.

#include <iostream>
#include <string>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/assign.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/asio.hpp>
using namespace boost;
using namespace std;

int main(int argc, const char * argv[]) {
    using namespace boost::asio;

    try {
        io_service ios;

        ip::tcp::acceptor acceptor(ios, ip::tcp::endpoint(ip::tcp::v4(), 6688));
        cout << acceptor.local_endpoint().address() << endl;

        while (true) {
            ip::tcp::socket sock(ios);
            acceptor.accept(sock);

            cout << "client:" ;
            cout << sock.remote_endpoint().address() << endl;
            sock.write_some(buffer("hello asio"));
        }
    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

更多 boost.asio 相关内容查看C++ 网络编程


2016-01-16 boost , C++

boost 学习笔记 10:Python

项目中需要将C++的程序暴露给网络使用,我也不想使用C++来用网络编程,就想到可以使用Python来解决Web端,然后将 C++ 的接口暴露给 Python 。于是在寻求解决方案的时候找到了 boost.python 库。

boost 中的 Python 库支持在 Python 和 C++ 之间的自由转换,包括 C++ 到 Python 的类型转换,默认参数,关键字参数,引用,指针等等。boost.python 库可以让 Python 轻易地调用 C++ 编写的模块,也可以很容易地在 C++ 中调用 Python 。

使用

C++ 文件中需要包含头文件

#include <boost/python.hpp>
using namespace boost::python;

还需要在链接的时候,加入 -lboost_python

以下操作借助Linux下g++完成,Windows可能需要借助其他工具,导出C++函数具体实现:

hello.cpp

char const* greet()
{
    return "hello, world";
}

#include <boost/python.hpp>

BOOST_PYTHON_MODULE(hello)			// Python 模块开始
{
    using namespace boost::python;		// 打开命名空间
    def("greet", greet);
}

Makefile

PYTHON_VERSION = 2.7
PYTHON_INCLUDE = /usr/include/python$(PYTHON_VERSION)

# location of the Boost Python include files and library
#  
BOOST_INC = /usr/local/include
BOOST_LIB = /usr/local/lib

# compile mesh classes
TARGET = hello

$(TARGET).so: $(TARGET).o
    g++ -shared $(TARGET).o -L$(BOOST_LIB) -lboost_python -L/usr/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) -o $(TARGET).so

$(TARGET).o: $(TARGET).cpp
    g++ -I$(PYTHON_INCLUDE) -I$(BOOST_INC) -fPIC -c $(TARGET).cpp

clean:
    rm *.so *.o

hello.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import hello
print hello.greet()

输出: hello, world

注意将 python, boost 所在目录 include 进去,在链接时加上 -lboost_python -lpython2.7 并 include python 和 boost目录。

Demo 地址GitLab : https://gitlab.com/einverne/boost_test/


2016-01-16 boost , C++

删除社交账号状态

这两天陆陆续续通过一些插件脚本删除了一些社交网站数据。年轻的时候发过一些无聊的状态,然后很久以后都没有登陆过的一些账号,倒不如关了的好,自此以后墙外只用 Google+ ,还有Blog记录一下所思所想,墙内公开内容除了豆瓣可能也没得发了,不愿生活在一个审查的制度下。虽然我可能也不会发什么敏感的内容,可谁知道什么敏感,什么不敏感呢?

facebook

Delete all facebook posts , 可以利用以下插件删除 Facebook 所有状态,包括账号内的头像等等。

Chrome Extension link

https://chrome.google.com/webstore/detail/facebook-timeline-cleaner/lfejocdlmhhkmnabbaeckmaehmgaffje

Update: 可惜了这个插件被删除了

renren

关闭账号

weibo

delete tool 删除工具 http://app.weibo.com/detail/62A7lB

批量删除weibo http://3.amfen.sinaapp.com/

删除微博评论 http://weibo333.com/

腾讯微博

设置中关闭账号

关闭QQ空间

通过以下链接申请删除QQ空间。

http://imgcache.qq.com/qzone/web/qzone_submit_close.html


2016-01-15 经验总结 , social , posts

间谍之桥 感悟

间谍之桥 Bridge of Spies 2015 影评

一名伟大的律师,成就一件伟大的人质交换。剧情7分,表演8分,娱乐7分。汤姆汉克斯的演技自然没得说,不过俄国人质的更加深入人心,虽然并不知道他的名字,但之后就再不会忘记他的名字 —- Mark Rylance 。而电影在娱乐性方面给人更多的是思考,沉浸在那段历史中,思考的是那段历史中人们做过的每一个决策。

原本以为这部影片是讲述“间谍”之间的故事,看到开场辩护时就知道被标题所骗。联系到最近的快播案,两国在司法上可谓天上地下。从1957年的《十二怒汉》开始,到这部《间谍之桥》50多年间好莱坞从未放弃探讨司法的公平性。而前半部分的辩护差点让我以为电影会从间谍故事转变成法庭辩护。幸而在后面美国侦察机被炸到苏联土地等情节,才让故事走上交换人质的主线。也让电影变得更加主旋律。

电影中最棒的两段台词:

第一段出现在CIA希望Donovan背弃律师的誓言泄露被告的信息时,Donovan告诉CIA探员的话:

I’m Irish, you’re German, but what makes us both Americans? Just one thing, one one one. The rule book. We call it the Constitution. We agree to the rules, and that’s what makes us Americans, it’s all that makes us Americans.

第二段是 Donovan和 Abel 之间的对话。

DONOVAN: You don’t seem alarmed. ABEL: Would it help?

电影剧本下载地址


2016-01-13 movie , 思考感悟 , american , action

boost 学习笔记 8:算法

对应书中第8章 算法,这一章作者介绍的很简单,只是举例使用 foreach , minmax ,其他算法都略去了。

foreach

将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;
}

minmax

在同一次操作中同时获取最大最小值。需包含头文件:

#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;
}

2016-01-12 boost , C++

boost 学习笔记 7:property_tree

上一篇文章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 可参考这篇文章 ,解释得非常清楚。


2016-01-11 boost , C++

boost 学习笔记 6:容器

对应书中的第七章容器与数据结构。先是讲了五个容器: array , dynamic_bitset, unordered, bimap和 circular_buffer. 他们都是对标准容器的扩充。

  • array 是对 C++内建数组的简单包装
  • dynamic_bitset 可容纳任意数量的二进制位
  • unordered 实现散列容器,非二叉树实现
  • bimap 是双向 map 扩展了std::map 的内容
  • circular_buffer 是循环队列。

tuple, any 和 variant 能够容纳不同类型容器

  • tuple 是对 std::pair 的泛化
  • any和 variant 都只能容纳一个可变类型的容器。any 可以持有任何类型数据,variant 需要在编译期指定类型。

最后 multi_arrayproperty_tree 两个组件使用组合模式实现复杂的数据结构。 multi_array 是一个泛型多维容器, property_tree 出自 1.41 版,可以解析 xml, son, ini 和 info 四种格式文件,在内部构造属性树。

对容纳元素基本要求:析构函数不能抛出异常

array

数组容器,包装了 C++ 内建数组,为其提供标准 STL 容器接口,begin(), front() 等等,性能与原始数组相差不大。但是 array 功能有限,当需要可变容量数组时,还是需要借助 std::vector 或者 boost::scoped_array

array 主要缺陷:

  • 没有构造函数,不能指定大小和初值
  • 没有 push_back() 和 push_front() ,不能动态增长
  • 不能搭配插入迭代器适配器功能

需包含头文件

#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;
}

dynamic_bitset

C++98 标准为处理二进制提供了两个工具: vector 和 bitset. 他们各自有优缺点: vector 可以动态增长,但不能方便地进行位运算;而 bitset 则刚好相反,可以方便地对容纳的二进制做位运算,但不能动态增长。 dynamic_bitset 正好填补了两者之间的空白。

需包含如下头文件

#include <boost/dynamic_bitset.hpp>
using namespace boost;

unordered

unordered 库提供两个散列集合类 unordered_setunordered_multiset ,同样 STLport 库也提供 hash_set 和 hash_multiset. 他们接口、用法和 STL 中标准关联容器 set/multiset 相同,只是内部使用散列代替二叉树实现,因此查找复杂度由对数降为常数。

散列容器 hash container 比二叉树的存储方式可以提供更高的访问效率。boost.unordered 库提供了一个完全符合 C++ 新标准草案 TR1 的散列容器实现,包括无序集合 set 和 无序映射 map.

unordered 库提供两个散列映射类 unordered_mapunordered_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;
}

bimap

可以容纳两个类型的元素,类似于 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 定义的集合类型包括如下:

  • set_of 可以作为键值 索引,有序且唯一,视图相当于 map
  • multiset_of 可以用作键值 索引,有序不唯一 ,视图相当于 multimap
  • unordered_set_of 可以作为键值,无序且唯一,视图相当于 unordered_map
  • unordered_multiset_of 可以作为键值,无序不唯一,视图相当于 unordered_multimap
  • list_of 不能作为键值,序列集合,无对应 STL 容器
  • vector_of 不能作为键值,随机访问集合,无对应 STL 容器
  • unconstrained_set_of 不能作为键值,无任何约束关系,无对应 STL 容器

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 还有很多高级用法,等用到的时候查阅文档吧。

circular_buffer

循环缓冲区数据结构,大小固定的循环队列。固定大小的缓存容量,当新增加的元素超过缓冲区的容量时,自动将最初的元素覆盖。

tuple

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;
}

any

特殊容器,只能容纳一个元素,但这个元素可以是任意类型—— 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;
}

variant

与 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 的区别

variant 和 any 都可以保存多类型的变量,但是他们的使用是有区别的。

  • 都可以容纳一个可变类型的元素,但是 variant 是有界类型,类型范围由用户指定,而 any 则是无界类型,可以容纳任意的类型
  • variant 可以在编译期类型检查
  • variant 提供泛型的 vistor 方式访问内部元素

multi_array

多维数组 的高效实现。 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

property_tree 容器比较复杂,它是一个保存了多个属性值得树形数据结构,功能强大,可以解析 xml, ini, json 和 info 四种格式的文本数据。单独拿一篇文章来讲它好了。


2016-01-10 boost , C++

星球大战:好莱坞流水线上的标准产物加上一些情怀催化一下

我果然不是星战迷,也没有星战情怀,相比同档期电影可以一看,但是我不是很喜欢这一部。 剧情6分(标准套路,困境解决困境),表演6.5(黑人演员可圈可点,女主没什么说的,机器人没有语言没有表情却异常的生动),娱乐性8分(一分光剑一分BB8)。

星战前六部,正传三部,前传三部,稍早的时候看过了,看原力觉醒之前没有认真补课。但是我知道好莱坞成熟流水线上的电影是不会要求你必须看完前六部再来看这一部电影的,每一部完整的电影都会有其完整的剧情和完整的人物描述。回到这一部原力觉醒,可能是星战迷内心的浴火被燃烧了,从第一部到今年三四十年的时间,足够让一个从青年变成中年甚至老年,伴随星战迷成长的电影总会伴随这一系列的讨论,今天早上看票房成绩已经是影史第四,超过票房第一的阿凡达已经是板上钉钉。基于这样的环境去影院看了。

剧情

就像之前说过的那样,这一部在剧情上的设定就是好莱坞标准的剧本设定,产生新的反派,然后需要正义人士组织反抗,制定计划一步一步瓦解反派,实在没有任何需要交代的内容。我甚至在观影过程中连续两次打哈欠,这实属罕见,在以前从来没有出现过,甚至在看《刺客聂隐娘》在场有人睡着的情况下我也没有困意,而这一部看到女主发觉拥有原力,Resistance组织开始制定作战计划开始就已经注定了结局。再到爱情,亲情的设定,总觉得会产生一些问题,大战刚刚结束,公主与将军的见面,再到后面父子的见面总感觉设定上有一些故意而为之。当然这些都是一些小的问题,总体来看剧情还是有一个及格的6分。至少前半部分,已经后面的一些情节,总能够让观众一边被主人公的台词表演逗笑,一边被剧情的紧张气氛而胆战心惊。

表演

再到表演,其实也并没有什么说得,反而到时那个萌萌的机器人能让观众会心一笑,有些时候表演并不需要语言和表情,一举一动都能够看出表演的出彩,或许这也是这部电影在表演上能给我留下的唯一印象,女主,黑人男主,再到哈里森福特,并没有什么特别出彩的地方。

BB 8

娱乐

观影风向标定下的娱乐性,其实一直不大明白,娱乐到底是指那一方面,如果是指话题性,新闻性,亦或是卖萌属性的话,就像上面说得那样我会一分给光剑,这一分给的是情怀,一分给BB8,那是因为这个“球”真是太可爱了,可爱到人人都会想要拥有一台。

总之这是一部让我觉得值得票价却也提不出什么优点的电影啦。感谢导演 JJ 艾布拉姆斯,感谢哈里森福特。


2016-01-09 思考感悟 , movie

guake zsh 配置小记

配置zsh guake 小记

Install zsh

sudo apt-get update && sudo apt-get install zsh

Install Oh-my-zsh

wget –no-check-certificate https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O – | sh

Make zsh default shell

chsh -s $(which zsh)

Get oh-my-zsh config

From here: https://github.com/robbyrussell/oh-my-zsh

Change theme

Edit zshrc config vim ~/.zshrc

ZSH_THEME="agnoster"

Install missing fonts

Install missing fonts here: https://github.com/Lokaltog/powerline-fonts After install missing font, change terminal font to “Melon xx”.

Refresh font cache

fc-cache -f -v

Install solarized scheme to guake

According to this: https://github.com/coolwanglu/guake-colors-solarized git clone this repo and run ./set_dark solarized .

Some config of guake

  • F12 to toggle guake
  • F11 to toggle full screen

Tab management

  • Alt + T for new tab
  • Alt + W for close current tab
  • Alt + N to go to previous tab
  • Alt + P to go to next tab

Clipboard

  • Alt + C for copy text to clipboard
  • Alt + V for paste text from clipboard

finally

guake zsh

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.

reference


2016-01-09 linux , guake , zsh , vim , agnoster , fonts , solarized

boost 学习笔记 5:文本字符串相关

字符串相关库,对应书中第五章 字符串与文本处理,大大增强了C++在文本处理上的能力。 lexical_cast 实现了字符串和数字之间的方便转换;format库提供了C++ 类似 printf() 的能力,用以格式化输出;string_algo 是一个算法库,提供了大量与字符串和文本处理相关的算法;tokenizer 库专注于文本处理领域的分词功能;xpressive 是一个灵活且功能强大的正则表达式解析库。

lexical_cast

之前单独有一篇文章讲 lexical_cast 这里不再重复。

format

format 基本集成了 printf 的格式化语法,每个 printf 格式化选项都以 % 符号开始,后面是格式规则,例如

  • %05d :输出宽度为5的整数,不足位用0填充
  • %-8.3f :输出左对齐,总宽度为8,小数位3位浮点数
  • % 10s :输出10位字符串,不足位用空格填充
  • %05X :输出宽度为5的大写16进制整数,不足位用0填充。

新增格式:

  • %|spec| : 竖线分割,区分格式化选项和普通字符
  • %N% : 标记第N个参数,相当于占位符,不带任何其他的格式化选项

主要用法

需要包含头文件

#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 还有很多高级的用法,参见文档。

string_algo

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 库命名遵循标准库惯例,算法名均为小写形式,并使用不同前缀或者后缀来区分不同版本,命名规则如下:

  • 前缀 i : 表示算法大小写不敏感,否则大小写敏感
  • 后缀_copy : 表示算法不变动输入,返回处理结果的拷贝,否则算法原地处理,输入即输出
  • 后缀_if : 需要判断式的谓词函数对象,否则使用默认的判断准则

string_algo 库提供算法共分为五大类:

  • 大小写转换
  • 判断式与分类
  • 修建
  • 查找与替换
  • 分割与合并

每一类算法中都会包含一系列函数。

tokenizer

主要特点

tokenizer 库是专门用于分词 token 字符串处理库,可以用简单方法把一个字符串分解成若干单词。

tokenizer 库可以容易地执行分词操作,但是它存在一些固有的缺陷。

  • 只支持单字符分割,当遇到“||”分割符时无能为力,智能自定义分词函数,或者使用 string_algo, 正则表达式等其他方法
  • 对wstring(unicode) 缺乏完善的考虑

主要用法

需包含头文件:

#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

正则表达式是处理文本强有力的工具,使用复杂的语法规则,能够解决文本处理领域绝大多数问题,诸如验证、匹配、查找、替换等等。xpressive 是一个先进的、灵活的、功能强大的正则表达式库,提供了对正则表达式全面的支持,而且比原正则表达式库 boost.regex 要好的是它不需要编译,速度快,同时语法又很类似。

xpressive 提供动态和静态两种方式。静态方式使用操作符重载生成编译期的表达对象,可以在编译期进行正则表达式的语法检查。动态的方式则是较传统的用法,与 boost.regex 和 Python 中的 re 模块相似,以字符串作为一个表达式对象,在运行时进行语法检查和处理。

正则表达式介绍

正则表达式定义了一套完善而复杂的语法规则,用于匹配特定模式的字符串,少量字符被用于定义特殊匹配模式语法,它们是: .^$()*+?{}[]\|。

  • 点号 (.) 匹配任意单个字符
  • ^ 尖角号 行开头
  • $ 行尾
  • () 括号,子表达式,可重复
  • * 星号,表前面元素可以重复任意多次 (n>=0)
  • + 加号,表前面元素可以重复一次或多次(n>0)
  • ? 问号,表前面的元素可以重复0次或者1次 (n=0,1)
  • {} 手动指定元素重复次数, {n}重复n次, {n,} 重复 >=n次, {n,m } 重复 n 到 m 次之间的次数, 即 n <= x <=m 次。
  • [] 定义字符集合
  • \ 转义字符
  • | 逻辑或的概念,匹配两侧的元素之一。

其他经常使用 \d 匹配数字 [0-9] , \w 匹配字母 [a-z] , \s 匹配空格等。

C++ 代码中的斜杠需要变成双斜杠,在使用正则表达式时,在语句前使用注释保存原始表达式,以方便未来的调试和维护。

  • basic_regex 是正则表达式的基本类,常用 sregexcregex 用于操作std::string ,和 C风格字符串。
  • match_results 保存正则匹配结果,常用 smatch 和 cmatch 用来支持 std::string 和 字符串。
  • sub_match 模板类类似迭代器对的对象,继承自 std::pair ,可以把它当成作一个字符串的区间。

主要用法

  • 混用两种方式,包含头文件 <boost/xpressive/xpressive.hpp>
  • 仅仅想使用静态方式,可以只包含头文件 <boost/xpressive/xpressive_static.hpp>
  • 仅仅想使用动态方式,可以只包含头文件 <boost/xpressive/xpressive_dynamic.hpp>

须有如下命名空间:

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;
}

2016-01-07 boost , C++

Google+

最近文章

  • vim presentation 大纲
  • Vim 寄存器 Vim 的寄存器可以看成 Vim 中额外用来存储信息的区域,虽然看不见,但是如果使用 x, s, y, p 等等命令的时候都无意识的使用到了 Vim 的寄存器(register).
  • vim normal 命令 替换::%s/^/#/g visual block:ggI# 注释第一行后用.重复执行每一行 我们可以在第三种方法之上用normal命令实现上述需求,步骤:
  • Vim 中的宏命令 Vim 的设计哲学中有这样一句话:”if you write a thing once, it is okay. However if you’re writing it twice or more times, then you should find a better way to do it”.
  • headless chrome puppeteer Headless 最早的时候在 PhantomJS 听说过这个概念,后来在 GitHub 各种项目中总有人不断提起这个概念,而最新看到的新闻便是 Chrome 开始支持 Headless,也正激起了我了解的欲望。