c++ {fmt}库使用指南一

一、缘起

夜已深,时针悄悄来到了十一点半,但我的思绪却像一股涌泉般汹涌澎湃,完全无法入眠。此时,我渴望做一些有意义的事情,决定借助这份宁静,沉下心来,撰写一份关于fmt库的使用指南。

fmt库是一个高效、易用的C++格式化库,可以帮助我们方便地进行字符串格式化、输出、日志记录等操作。在这份指南中,我将介绍fmt库的基本用法、格式化字符串语法、异常处理机制等方面的内容,希望能为大家提供帮助。让我们一起开始吧!

二、基本使用 安装fmt库

github:

api指南:

项目中引入fmt库 老方法 cmake (不推荐)

mkdir build

cd build

cmake …

make 或者使用ide打开生成的项目文件生成相应的库静态库\仅仅包含头文件,(需要在包含头文件之前#define FMT_HEADER_ONLY 推荐) Hello World

    #define FMT_HEADER_ONLY 
    #include "fmt/core.h"
    #include 
    int main()
    {
        // {} 占位符,可以占位int float double ....
        std::string world = fmt::format("Hello {}", "World");
        fmt::print("{}", world);
    }

三、 字符格式化语法

格式化函数如 fmt::format() 和 fmt::print() 都使用相同的语法,它由 {} 包围的“替换字段”。

未包含在花括号中的任何内容都被视为文字文本,将不加修改地复制到输出中。果需要在字面文本中包含一个花括号字符,可以通过重复使用花括号来转义:{{ 和 }}。

在大多数情况下,语法与 printf 格式相似,但添加了 {} 并使用 : 代替 %。例如,“.2f” 可以转换为 “{:03.2f}”,只是把%替换了{} 但是fmt功能更强大

输出格式如下:

replacement_field ::= “{” [arg_id] [“:” (format_spec | chrono_format_spec)] “}” // 替换字符= {[参数id]:[format_spec] | [chrono_format_spec]}

arg_id ::= integer | identifier // 整数0-9 a-z A-Z, 下面的是表示哪个代表什么意思

integer ::= digit+

digit ::= “0”…“9”

identifier ::= id_start id_continue*

id_start ::= “a”…“z” | “A”…“Z” | “_”

id_continue ::= id_start | digit\

替换格式以 “:” 为分界符,“:” 前面的的代表参数id, 就是指参数的顺序,可以是1、2、3、4、… 也可以是a、b 、c … “:” 后面的就是专门针对数字型(整形、浮动点型) 时间类型定义的格式。[] 代表是可选的, | 代表或,只能存在一种

3.1参数id 在":" 之前

    // 只有参数id时候,: 可以省略不写
    fmt::print("name:{1}, age: {0:}", 42, "knox");

3.2format_spec 在":" 之后 (Format Specification Mini-Language 格式化规范迷你语言)

组成

format_spec ::= [[fill]align][sign][“#”][“0”][width][“.” precision][“L”][type]

fill ::=

align ::= “” | “^”

sign ::= “+” | “-” | " "

width ::= integer | “{” [arg_id] “}”

precision ::= integer | “{” [arg_id] “}”

type ::= “a” | “A” | “b” | “B” | “c” | “d” | “e” | “E” | “f” | “F” | “g” | “G” |

“o” | “p” | “s” | “x” | “X”\

file 代表填充字符,填充字符可以是除了“{”和“}”之外的任何 Unicode 代码点。填充字符的存在是由其后面的字符表示的,该字符必须是对齐选项之一。如果 format_spec 的第二个字符不是有效的对齐选项(、^),则假定填充字符和对齐选项都不存在。

align 代表对其方式 ,< 代表左对齐, >代表右对齐, ^代表居中

sign 只针对数字,“+”表示正数和负数都要使用符号。“-”表示只有负数需要使用符号(这是默认行为)。空格表示正数前面要加一个空格,负数前面要加一个减号。

此选项仅适用于整数和浮点数类型。对于整数,当使用二进制、八进制或十六进制输出时,此选项会将相应的前缀“0b”(“0B”)、“0”或“0x”(“0X”)添加到输出值中, 小写字符格式出来的是小写,如,{:#0X}, 255 = 0XFF, ,{:#0x}, 255 = 0xff, 其他的进制类似,

width 十进制的整数,只适用于数值型,用于定义最小字段宽度。如果未指定,则字段宽度将由内容确定。在宽度字段之前加上零(‘0’)字符可以启用数值类型的符号感知零填充。

它强制在符号或基数(如果有)之后但在数字之前放置填充。这用于以“+000000120”形式打印字段。

“.” precision 代表精度。精度只存在于 浮点型中,整数、字符、布尔和指针值,是不允许使用精度的,对于非数字类型,字段指示最大字段大小,就算指定了大小。C字符串必须以空字符结尾.

一般精度.nf, 不是精度.n n代表需要格式化几个。

    // 非数字指定的是输出的字符的个数。
    fmt::print("name:{1}, age: {0:.5}", "1234567890", "knox");
    // 输出:name:knox, age: 12345
    
    // c字符串不够怎么办呢,最大字符串长
    fmt::print("name:{1}, age: {0:.5}", "123", "knox");
    // 输出:name:knox, age: 123
    
    // 对于数字代表精度,只对浮点型有用
    fmt::print("{:.2f}", 42.0f);
    // 输出:42.00
    //fmt::print("{:.2f}", 42); 编译报错
    //fmt::print("{:.2f}", true); 编译报错

“L”选项使用当前区域设置来插入适当的数字分隔符。此选项仅适用于数值类型。

    auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
    fmt::print("{}", s);
    // 输出: 1,234,567,890

type

'e’指数表示法。指数标记使用小写字母 ‘e’。

'E’指数表示法。指数标记使用大写字母 ‘E’。

'f’定点表示法。将数字显示为定点数。

'F’定点表示法。将数字显示为定点数。与 ‘f’ 相同。

'g’通用格式。根据数字的大小和指定的精度,使用定点表示法或指数表示法。

'G’通用格式。与 ‘g’ 相同,但使用指数标记使用大写字母 ‘E’。

'x’十六进制整数。将数字显示为十六进制数。

'X’十六进制整数。将数字显示为大写十六进制数。

'a’十六进制浮点数。使用小写字母 ‘a’ 作为指数标记。

'A’十六进制浮点数。使用大写字母 ‘A’ 作为指数标记。

'c’字符。将整数解释为 Unicode 字符。

's’字符串。将参数格式化为字符串。

'p’指针。将指针格式化为十六进制数。 chrono_format_spec 时间格式化

1.组成

chrono_format_spec ::= [[fill]align][width][“.” precision][chrono_specs]

chrono_specs ::= [chrono_specs] conversion_spec | chrono_specs literal_char

conversion_spec ::= “%” [modifier] chrono_type

literal_char ::= \ // 除了{ } % 这三个字符都可以做链接符

modifier ::= “E” | “O”

chrono_type ::= “a” | “A” | “b” | “B” | “c” | “C” | “d” | “D” | “e” | “F” |

“g” | “G” | “h” | “H” | “I” | “j” | “m” | “M” | “n” | “p” |

“q” | “Q” | “r” | “R” | “S” | “t” | “T” | “u” | “U” | “V” |

“w” | “W” | “x” | “X” | “y” | “Y” | “z” | “Z” | “%”\

[[fill]align] 与3.2.1 相似天数小于10,分钟数,秒数,月数,都会在前面添加0

关于fmt 格式化字符串更详细的语法请移步 格式化字符串示例 按arg_id 顺序输出,id从0开始

    // 序号从零开始
    fmt::print("{0}, {1}, {2}\n", 'a', 'b', 'c');
    // print: "a, b, c"
    fmt::print("{}, {}, {}\n", 'a', 'b', 'c');
    // print: "a, b, c"
    fmt::print("{2}, {1}, {0} \n", 'a', 'b', 'c');
    // print: "c, b, a"
    // fmt::print("{2}, {1}, {0} {3}\n", 'a', 'b', 'c'); 编译报错,没有第四个参数
    // 输出
    // a, b, c  
    // a, b, c  
    // c, b, a  

用自定的字符填充空白符,并指定居中方式

    // 不指定填充符号默认为空格, 如果不存在 <>^ 就假定填充符号都不存在
    fmt::print("{:<30}\n", "left aligned");
    // 
    fmt::print("{:<<30}\n", "left aligned");
                
    fmt::print("{:>30}\n", "right aligned");
    fmt::print("{:>>30}\n", "right aligned");
    fmt::print("{:^30}\n", "centered");
          
    fmt::print("{:^^30}\n", "centered"); 
    // 输出
    //left aligned                  
    //left aligned<<<<<<<<<<<<<<<<<<
    //                right aligned 
    //>>>>>>>>>>>>>>>>>right aligned
    //        centered              
    //^^^^^^^^^^^centered^^^^^^^^^^^

动态设置宽度和精度

    // 可以动态设置宽度和精度,但仅仅限制于此,
    // 动态设置宽度的时候,宽度arg_id 为 参数+1, 
    //           0 1   2 3  参数arg_id 可以数{ 的个数,当然{} 一定是成对出现的。
    fmt::print("{:<{}} {:.{}f} \n", "left aligned", 30, 3.14, 1);
    fmt::print("{:.{}f}\n", 3.14, 1);
    // 输出
    // left aligned                   3.1  
    // 3.1  

:+ :- 号的使用

    // + 代表正数加+号,负数加-号
    fmt::print("{:+f}; {:+f}\n", 3.14, -3.14); 
    // 空格正数加空格,负数加-号
    fmt::print("{: f}; {: f}\n", 3.14, -3.14); 
    // -号代表正数不变,负数加-号 same as '{:f}; {:f}' 相当于是默认行为
    fmt::print("{:-f}; {:-f}\n", 3.14, -3.14);
    fmt::print("{:+}; {:+}\n", 3, -3);
    fmt::print("{:-}; {:-}\n", 3, -3);
    fmt::print("{: }; {: }\n", 3, -3);
    fmt::print("{:}; {:}\n", 3, -3);
    // 输出
    //+3.140000; -3.140000
    // 3.140000; -3.140000
    //3.140000; -3.140000
    //+3; -3
    //3; -3
    // 3; -3
    //3; -3

进制输出

    // # 加上符号 0x 0 0b
    fmt::print("int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}\n", 42);
    
    fmt::print("int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}\n", 42);
    // #06 代表宽度为6个, 不够的在进制之前使用0填充, 超出指定大小被忽略
    fmt::print("int: {0:d};  hex: {0:#06x};  oct: {0:#06o};  bin: {0:#06b}\n", 42);
    fmt::print("int: {0:d};  hex: {0:#01x};  oct: {0:#02o};  bin: {0:#03b}\n", 42);
    // 输出
    // int: 42;  hex: 2a;  oct: 52; bin: 101010
    // int: 42;  hex: 0x2a;  oct: 052;  bin: 0b101010
    // int: 42;  hex: 0x002a;  oct: 000052;  bin: 0b101010
    // int: 42;  hex: 0x2a;  oct: 052;  bin: 0b101010

使用填充字符打印边框

    fmt::print(
        "┌{0:─^{2}}┐\n"
        "│{1: ^{2}}│\n"
        "└{0:─^{2}}┘\n", "", "Hello, knox!", 20);

有点抗不住了,今天就先到这里了,明天我们继续刚fmt库的api详细用法。

Bokeh,一个交互式可视化Python库!

Bokeh - Python数据可视化的新玩法

数据可视化在Python里有好多选择,今天咱聊个好玩的库 - Bokeh。它跟别的画图工具不太一样,整出来的图表都是可以交互的,鼠标放上去能显示数据,还能放大缩小,特别适合做一些炫酷的数据展示。

安装那些事

安装特别简单,一行代码就搞定:

pip install bokeh

温馨提示:建议用pip安装最新版,conda源的版本可能会偏老。

整个简单图表试试水

先来个最基础的折线图:

from bokeh.plotting import figure, show from bokeh.io import output_notebook # 准备数据 x = [1, 2, 3, 4, 5] y = [2, 5, 8, 2, 7] # 创建画布 p = figure(title=“我的第一个Bokeh图表”, width=400, height=300) # 画折线 p.line(x, y, line_width=2) # 显示图表 show(p)

这段代码运行完,就能看到一个可以交互的折线图,把鼠标放到线上还能看到具体数值,右边还有一排工具按钮,可以缩放、平移,贼方便。

添加点互动效果

光有线太单调了,加点花里胡哨的效果:

from bokeh.models import ColumnDataSource from bokeh.models import HoverTool # 数据打包 source = ColumnDataSource(data={ 'x': [1, 2, 3, 4, 5], 'y': [2, 5, 8, 2, 7], 'desc': ['A', 'B', 'C', 'D', 'E'] }) p = figure(title=“带标签的图表”) # 加个圆点 p.circle('x', 'y', size=10, source=source) # 鼠标悬停显示标签 hover = HoverTool(tooltips=[ ('位置', '@x, @y'), ('标签', '@desc') ]) p.add_tools(hover) show(p)

布局排排坐

想在一个页面上放多个图表?没问题:

from bokeh.layouts import row, column p1 = figure(title=“图表1”) p1.line([1,2,3], [4,5,6]) p2 = figure(title=“图表2”) p2.circle([1,2,3], [2,4,6]) # 横着排 show(row(p1, p2)) # 竖着排也行 # show(column(p1, p2))

温馨提示:布局组件可以随意嵌套,想咋排就咋排。

本站内容来自用户投稿,如果侵犯了您的权利,请与我们联系删除。联系邮箱:835971066@qq.com

本文链接:http://news.xiuzhanwang.com/post/1337.html

发表评论

评论列表

还没有评论,快来说点什么吧~

友情链接: