使用boost::format库进行类似python的字符串格式化

因为boost::format库使用类似stringstream类来进行格式化,所以不需要指定参数的类型,例如%d, %f, %c等,直接指定参数位置就可以了。
可以实现类似python的字符串格式化效果。
对于格式化字符 %本身,可以使用两个 %%来进行转义。
程序代码如下,
CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(lexical_cast)

add_definitions(-std=c++14)

include_directories("/usr/local/include")
link_directories("/usr/local/lib")
file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach( sourcefile ${APP_SOURCES} )
    file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
    string(REPLACE ".cpp" "" file ${filename})
    add_executable(${file} ${sourcefile})
    target_link_libraries(${file} boost_filesystem boost_thread boost_system boost_serialization pthread boost_chrono)
endforeach( sourcefile ${APP_SOURCES} )

main.cpp

#include 
// 注意转义字符 %% 表示 一个 %的用法

#include 

class i_hold_some_internals {
    int i;
    std::string s;
    char c;

    public:
        i_hold_some_internals():
            i(100),
            s("Reader"),
            c('!')
         {}

        // 格式化参数必须包含下面的字符
        // %1% i
        // %2% s
        // %3% c
        std::string to_string(const std::string& format_specifier) const {
            boost::format f(format_specifier);
            // 去掉too_many_args_bit位,保留其他位
            unsigned char flags = boost::io::all_error_bits;
            flags ^= boost::io::too_many_args_bit;
            f.exceptions(flags);
            return (f % i % s % c).str();
        }
};

int main(int argc, char* argv[]) {
    i_hold_some_internals class_instance;
    std::cout << class_instance.to_string(
        "Hello, dear %2%! "
        "Did you read the book for %1% %% %3%\n");
    
    std::cout << class_instance.to_string(
        "%1% == %1% && %1% %% != %1%\n\n"
    );

    // 输出 "Reader"
    std::cout << class_instance.to_string("%2%\n\n");

    try {
        class_instance.to_string("%1% %2% %3% %4% %5%\n");
    } catch(const std::exception& e) {
        std::cerr << e.what() << '\n';
    }
}

程序输出如下,


图片.png

原理解析,请看下图,


图片.png

我们看下basic_format类的一些参数定义,


图片.png

每一个格式化选项被抽象成了一个item对象, std::vector items_; 代表所有格式化选项的集合。
std::vector bound_; 代表当前处理了多少元素,这个数组的大小与格式化选项的个数相同,例如我已经处理完了 %1, %2, 现在到了 %3,总共有5个格式化选项,那么现在的bound_状态是 std::vector bound_{true, true, true, false, false}。

int cur_arg_;是当前处理的arg数,从0开始。 还是上面的例子,如果现在是 %3,那么 int cur_arg=2。

int num_args_; 总共的格式化参数个数,如果是上面的例子, int num_args_=5。

mutable bool dumped_; 是否已经调用过 str()方法,如果调用过,说明已经格式化过一次了。重新格式化的话,要清空重来。

string_type prefix_; 第一个格式化元素之前需要插入的前缀。

详细的代码可以自己去看,完全和我的解释项应证。

所以这里还需要理解的一个东西就是 每一个格式化元素被映射成了一个格式化选项format_item_t,format_item_t是个什么东西?

看一下format_item_t的一个成员列表


图片.png

argN,当前处理到的参数号。从0开始,和basic_format中的cur_arg相对应。

string_type res; 当前 格式化字符替换后的结果,例如 %1%需要被替换成100,这里的res就是std::string res = "100"。

string_type appendix_; 当前格式化字符和下一个格式化字符之间的字符串。

其他的成员就没那么重要了。

我们再来看basic_format类的 % 号操作符重载 operator%(const T& x)。
直接跳到feed_impl方法


图片.png

feed_impl方法又调用了一个distribute方法,


图片.png

distribute方法的上半部分反映了最前面代码中设置异常标志位的意义,只有对应异常的异常标志位为1,才会抛出相应的异常。
下面一部分的put方法,意图就比较明显了,使用buf_做缓冲区,把x中的内容填充到当前item的res字段中。
这样逐个 格式化选项处理完毕之后,

basic_format类的items_字段中就包含了所有格式化所需要的信息。

我们接着看 basic_format::str()方法


图片.png

str方法就是简单的把items_中的内容拼接起来,然后返回一个std::string。
最后把dumped字段设置为true,表示之前已经格式化过一次了。

你可能感兴趣的:(使用boost::format库进行类似python的字符串格式化)