确定包含转义字符的字符串的 print-size

Determine the print-size of a string containing escape characters

我正在尝试制作一个进度条,它会根据屏幕上剩余的 space 调整大小。进度条由一个标题字符串组成,后跟进度条和一些尾随数字:

15:23:11 [SampleElement] SampleElement.cpp:25: Finding bin index... [###########] 100% (14K it/s)

原则上这是一个非常简单的任务,因为 print-size 可以直接通过标题的大小 + pBar 的大小推导出来。

然而,当标题字符串包含转义字符(例如颜色)时,执行 title.size() 不仅会 returns 屏幕上的打印尺寸,还会显示非打印字符。我的问题是:有没有一种方法可以简单地计算任何字符串的 print-size?

您可以使用正则表达式搜索 ANSI 终端转义序列,因为它们具有独特的模式。顺便说一下,有一个名为 isprint(x) 的 C 函数可以检查可打印字符。

结合这两者,您应该能够创建一个可以计算字符串中可打印字符的函数。 (假设有问题的终端支持 当然是 ANSI 转义 codes/sequences。)

// The following only works with C++11 or above

// ...
#include <algorithm>
#include <string>
#include <cctype>
#include <regex>

// The regular expression is brought outside the function in order to avoid compiling it multiple times during each call to 'count_no_escape'
std::regex ansi_reg("3((\[((\d+;)*\d+)?[A-DHJKMRcf-ilmnprsu])|\(|\))");

std::string::iterator::difference_type count_no_escape(std::string const& str) {
    std::string::iterator::difference_type result = 0;
    std::for_each(std::sregex_token_iterator(str.begin(), str.end(), ansi_reg, -1),
        std::sregex_token_iterator(), [&result](std::sregex_token_iterator::value_type const& e) {
                                          std::string tmp(e);
                                          result += std::count_if(tmp.begin(), tmp.end(), isprint);
                                      });
    return result;
}

Small Note: The regex for checking ANSI escape sequences was built using this webpage as reference:

上述函数使用 ANSI 转义码作为分隔符对字符串进行标记化。提取所有可能的子串后,计算每个子串中的可打印字符,并返回总和结果。

现在你可以这样使用了:

// ...
std::cout << count_no_escape("3[1;31mabcd\t\n3[7h") << std::endl; // 4
// ...

如果您想亲自尝试一下,请点击:

Live example