我在使用 ruby​​ printf 时发现了这一点,但它也适用于 C 的 printf。

如果在输出字符串中包含 ANSI 颜色转义代码,则会弄乱对齐方式。

红宝石:

ruby-1.9.2-head > printf "%20s\n%20s\n", "\033[32mGreen\033[0m", "Green"
      Green          # 6 spaces to the left of this one
               Green # correctly padded to 20 chars
 => nil

C 程序中的同一行会产生相同的输出。

无论如何,有没有办法让 printf (或其他东西)对齐输出而不为非打印字符添加空格?

这是一个错误,还是有充分的理由?

更新: 由于当存在 ANSI 代码和宽字符时,不能依赖 printf 来对齐数据,因此是否有最佳实践方法可以在 ruby​​ 控制台中排列彩色表格数据?

有帮助吗?

解决方案

我不同意您对绿色绿色后9个空间的特征。我使用Perl而不是Ruby,但是如果我使用您的语句修改,在字符串后打印管道符号,我会得到:

perl -e 'printf "%20s|\n%20s|\n", "\033[32mGreen\033[0m", "Green";'
      Green|
               Green|

这向我表明了 printf() 语句在字符串中计算了14个字符,因此它预先固定了6个空间,以制作20个字符的直接对准。但是,终端吞下了其中9个字符,将其解释为颜色变化。因此,输出显示的9个字符比您想要的短。然而 printf() 第一个“绿色”之后,没有打印9个空白。


关于对齐输出的最佳实践(与颜色),我认为您需要将每个尺寸和对准的字段包围着简单的“%s”字段,这些字段涉及颜色:

printf "%s%20.20s%s|%s%-10d%s|%s%12.12s%s|\n",
       co_green, column_1_data, co_plain,
       co_blue,  column_2_data, co_plain,
       co_red,   column_3_data, co_plain;

显然,在哪里 co_XXXX 变量(常数?)包含要切换到命名颜色的逃生序列(和 co_plain 可能会更好 co_black)。如果事实证明您不需要在某些字段上进行颜色,则可以使用空字符串代替 co_XXXX 变量(或调用 co_empty).

其他提示

这不是一个错误:Ruby不应该知道(至少在printf中,对于像诅咒之类的东西是另一个故事),它的Stdout将进入一个了解VT100逃生序列的终端。

如果您没有调整背景颜色,那么这样的事情可能是一个更好的主意:

GREEN = "\033[32m"
NORMAL = "\033[0m"
printf "%s%20s%s\n", GREEN, "Green", NORMAL

printf 字段宽度指示符对于对齐表格数据,接口元素等都没有用,除了您已经发现的控制字符的问题外,还有非课程和双宽字符,如果您不don',您的程序还必须处理这些字符。 T希望将内容限制为旧字符编码(许多用户认为已弃用)。

如果您坚持使用 printf 这样,您可能需要做类似的事情:

printf("%*s\n%*s\n", bytestopad("\033[32mGreen\033[0m", 20), "\033[32mGreen\033[0m", bytestopad("Green", 20), "Green");

在哪里 bytestopad(s,n) 是您编写的函数,该函数计算需要多少个字节(字符串加填充空间)才能导致字符串 s 占用 n 终端列。这将涉及解析逃脱和处理多材料字符并使用设施(例如Posix wcwidth 函数)查找每个终端列。注意使用 * 代替恒定的场宽度 printf 格式字符串。这使您可以通过 int 争论 printf 用于运行时变量的字段宽度。

我会从实际文本中分离出任何转义序列,以避免整个问题。

# in Ruby
printf "%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green"

或者

/* In C */
printf("%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green");

由于 ANSI 转义序列不是 Ruby 或 C 的一部分,因此它们并不认为需要特殊对待这些字符,而且理应如此。

如果您要做很​​多终端颜色的工作,那么您应该研究curses 和ncurses,它们提供了适用于许多不同类型终端的颜色更改功能。它们还提供更多的功能,例如基于文本的窗口、功能键,有时甚至是鼠标交互。

这是我最近提出的解决方案。这使您可以使用 color("my string", :red) 在一个 printf 陈述。我喜欢使用相同的格式字符串作为标头和数据 - 干燥。这使得这是可能的。另外,我使用 彩虹 宝石生成颜色代码;这不是完美的,但要完成工作。这 CPAD 哈希分别包含每个颜色的两个值,分别对应于左右填充。自然,应扩展该解决方案,以促进其他颜色和修饰符,例如大胆和下划线。

CPAD = {
  :default => [0, 2],
  :green   => [0, 3],
  :yellow  => [0, 2],
  :red     => [0, 1],
}

def color(text, color)
  "%*s%s%*s" % [CPAD[color][0], '', text.color(color), CPAD[color][1], '']
end

例子:

puts "%-10s   %-10s   %-10s   %-10s" % [
  color('apple',  :red),
  color('pear',   :green),
  color('banana', :yellow)
  color('kiwi',   :default)
]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top