STL 格式






4.23/5 (11投票s)
将您喜欢的格式字符串和函数参数放入 STL 字符串。
引言
如今,许多具有用户界面的应用程序肯定会使用字符串操作例程。程序员有权为特定情况选择最佳且最方便的工具。我猜最古老的一种应该是标准库函数“printf”及其派生函数。为什么还要一个类似 printf 的函数?因为它很有趣,并且应该在特定情况下有所帮助。有兴趣吗?请继续阅读……
替代方案
您可以根据自己的喜好选择任何格式来格式化您的字符串。我猜您至少知道其中一种适合您。我可以列出一些我所知道并用于日常工作的格式:STL (streams)、MFC/WTL (CString)、CRT/libc(printf)、boost::format,在 https://codeproject.org.cn 上也有一些类似的文章。现在,我将我的格式函数添加到此列表中。
我不喜欢流,因为如果您需要以特定格式向其中添加内容,您需要调用许多额外的函数,如“width, setf”等。如果您有大量文本要流式输出,并且需要更改多种格式,这会很不方便。因此,替代方法是“CString”类和/或“printf”函数,因为您“调用”所有这些函数都带有格式字符串和参数列表。“CString”类相当不错,但它非常特定,如果您为多个平台编写程序,可能无法使用它。函数“printf”很好,但您需要知道它将输出多少个字符,您不会有动态缓冲区。有没有其他选择?Boost 库,但我不喜欢它的速度。我承认,我没有测试过,但我看到了网上的结果,我不喜欢它们。还有什么其他选择?自己写一个,然后享受它。
开端
安全性在编程世界中是第一位的。嗯,您不会从“printf”和我的格式函数中获得这种安全性。它们都使用相同的“stdarg”机制,如果您知道自己在做什么,这很好。但如果您想破坏应用程序,您可以轻松更改格式字符串和/或参数顺序。您应该考虑到,有了安全性,您就会牺牲速度,并选择适合您的方法。
那么,让我们更仔细地看看,我们有什么样的“重新发明轮子”?我阅读了很多关于字符串格式的知识,并做出了决定:我的格式库将非常接近 printf 的“标准”。为什么?因为它非常方便,并且已经在我脑海中根深蒂固,而且很难说服其他程序员使用带有新格式的库。这不明智。所以,这是:旧格式带有一些奇怪的增强功能
%[<|><{>}][flags][:padchar][width][.precision]type-char[<|><}>]
[flags] 可选标志。
'-':左对齐(默认右对齐)
'=':居中对齐
'+':显示符号
'!':不打印*0*的整数或*null*的字符串
'L':使用 long 而不是 int
'LL':使用 long long 而不是 long
'0':用填充字符填充(如果未指定填充字符,则用 0 填充)
'#':显示基数。o- 0,x- 0x,X- 0X
[:padchar] 可选标志。默认值取决于 [flags]。
[width] 可选标志。指定转换结果字符串的最小宽度。
[.precision] 可选标志。输出浮点数时,它设置数字的最大位数。与 type-char s 或 S 一起使用时,转换字符串将截断为前几个字符。
type-char:
'b':二进制输出
'o':八进制输出
'i', 'u', 'd':十进制输出(有符号,无符号)
'x':十六进制输出('X' 大写)
'f':固定浮点格式
's', 'S':字符串输出
'c', 'C':字符输出
'%':打印 '%'
我想,如果您使用类似 printf 的格式字符串,您会发现以上格式中一些熟悉的东西。新的是“padchar”。我没有找到类似的功能(STL 流除外),所以我悄悄地添加了它。
使用代码
要使用我的函数,您需要包含 vformat.h 文件。主函数和所有结构都位于“frmt”命名空间下。您可以选择添加“using namespace frmt;”行,或者使用“frmt::”前缀调用函数。为了使事情更简单,更像 WindowsAPI,您可以创建附加函数
size_t formatA (string& sOut, const char *cpcFormat, ... ) { va_list vargs; va_start (vargs, cpcFormat); size_t iRes = vformat<char> (sOut, cpcFormat, vargs); va_end (vargs); return iRes; } size_t formatW (wstring& sOut, const wchar_t *cpwcFormat, ... ) { va_list vargs; va_start (vargs, cpwcFormat); size_t iRes = vformat<wchar_t> (sOut, cpwcFormat, vargs); va_end (vargs); return iRes; }
在调试版本中检查“iRes”变量是很明智的,因为它显示了格式字符串中的错误位置(0 - 表示成功)。
关注点
我敢打赌您想看看我的格式函数有多快?嗯,我不得不让您失望:它不像我或您期望的那么快,但它很有潜力。在某些情况下,它的速度与 CRT/libc printf 非常相似,但在大多数情况下,它会稍慢一些。看看速度表,您就会明白(D 表示调试,R 表示发布)(时间单位为毫秒)
Format string |
FORMAT (D) |
printf (D) |
FORMAT (R) |
printf (R) |
%i |
4844 |
1109 |
421 |
688 |
%-#4x %+#012x %+#012o %#8x |
14813 |
4203 |
2906 |
2563 |
%-#4x |
5359 |
1110 |
547 |
656 |
%+#012x |
5625 |
1312 |
640 |
782 |
%+#012o |
5438 |
1234 |
547 |
703 |
%0#-+3.5s %0#-+5.3s %0#-+s |
9688 |
2078 |
1343 |
1094 |
好了,数字就是数字,它们不言自明。调试版本肯定很慢,我对此无能为力,但发布版本很有潜力。随着格式字符串的复杂性增加,我的函数的运行时间与 printf 的运行时间非常接近。另外,请注意一个非常有趣的现象:当格式字符串变长时,printf 函数的时间增长速度远快于我的函数。这非常有趣且结果令人啼笑皆非。
最后的寄语
这个函数是我生活中一次“重新发明轮子”的小尝试。我还会用它吗?是的!我想编写一些与 STL string 类似的东西,因为我非常怀念 STL 中的这个功能。最终,我完成了这个,而且,我将它发布到互联网上供大家评判。如果您开始使用我的函数并对其感到满意,请给我写一封简短的便条。您可以随意在任何产品中使用它,但不要声称是您自己写的。
历史
- 字符串格式中的一个小 bug 修复:'c' 和 'C'。
- 添加了额外的 ifdef 以便在 linux 系统下编译代码。