我不理解两件事情。
(1) 这是你的代码,在你的控制下。你想要给你的数据添加转义序列,然后再将它们剥离出来,以便计算数据的长度??在添加转义序列之前计算填充似乎更简单。我错过了什么吗?
假设没有任何转义序列会改变光标位置。如果有,当前被接受的答案也无法正常工作。
假设你有每列字符串数据(在添加转义序列之前)的列表,名为string_data
,预定的列宽度在名为width
的列表中。尝试像这样:
temp = []
for colx, text in enumerate(string_data):
npad = width[colx] - len(text)
assert npad >= 0
enhanced = fancy_text(text, colx, etc, whatever)
temp.append(enhanced + " " * npad)
sys.stdout.write("".join(temp))
更新-1
根据OP的评论:
我想要去除它们并计算包含颜色代码的字符串长度的原因是因为所有数据都是通过编程构建的。我有一堆着色方法,正在构建数据,就像这样: str = "%s/%s/%s" % (GREEN(data1), BLUE(data2), RED(data3))
在事后给文本上色将非常困难。
如果数据由各种格式的片段组成,仍然可以计算显示长度并适当填充。下面是一个函数,用于处理一个单元格的内容:
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(40, 48)
BOLD = 1
def render_and_pad(reqd_width, components, sep="/"):
temp = []
actual_width = 0
for fmt_code, text in components:
actual_width += len(text)
strg = "\x1b[%dm%s\x1b[m" % (fmt_code, text)
temp.append(strg)
if temp:
actual_width += len(temp) - 1
npad = reqd_width - actual_width
assert npad >= 0
return sep.join(temp) + " " * npad
print repr(
render_and_pad(20, zip([BOLD, GREEN, YELLOW], ["foo", "bar", "zot"]))
)
如果你觉得这个调用被标点符号压垮了,你可以这样做:
BOLD = lambda s: (1, s)
BLACK = lambda s: (40, s)
def render_and_pad(reqd_width, sep, *components):
x = render_and_pad(20, '/', BOLD(data1), GREEN(data2), YELLOW(data3))
(2) 我不明白为什么你不想使用Python自带的正则表达式工具包?没有涉及到任何“hackery”(我知道的任何可能的“hackery”含义):
>>> import re
>>> test = "1\x1b[a2\x1b[42b3\x1b[98;99c4\x1b[77;66;55d5"
>>> expected = "12345"
>>>
... regex = re.compile(r"""
... \x1b # literal ESC
... \[ # literal [
... [;\d]* # zero or more digits or semicolons
... [A-Za-z] # a letter
... """, re.VERBOSE)
>>> print regex.findall(test)
['\x1b[a', '\x1b[42b', '\x1b[98;99c', '\x1b[77;66;55d']
>>> actual = regex.sub("", test)
>>> print repr(actual)
'12345'
>>> assert actual == expected
>>>
更新-2
根据评论:
我仍然更喜欢Paul的答案,因为它更加简洁。
比什么更加简洁呢?以下的正则表达式解决方案难道不够简洁了吗?
import re
strip_ANSI_escape_sequences_sub = re.compile(r"""
\x1b # literal ESC
\[ # literal [
[;\d]* # zero or more digits or semicolons
[A-Za-z] # a letter
""", re.VERBOSE).sub
def strip_ANSI_escape_sequences(s):
return strip_ANSI_escape_sequences_sub("", s)
raw_data = strip_ANSI_escape_sequences(formatted_data)
[在@Nick Perkins指出代码无法工作后,上述代码已得到更正]