使用xml-like标记生成彩色终端文本
项目描述
Ansimarkup
Ansimarkup是一个用于生成彩色终端文本的XML-like标记。
from ansimarkup import ansiprint as print
print("<b>bold text</b>"))
print("<red>red text</red>", "<red,green>red text on a green background</red,green>")
print("<fg #ffaf00>orange text</fg #ffaf00>")
安装
可以从PyPi安装ansimarkup的最新稳定版本。
python3 -m pip install ansimarkup
使用方法
基本
from ansimarkup import parse, ansiprint
# parse() converts the tags to the corresponding ansi escape sequence.
parse("<b>bold</b> <d>dim</d>")
# ansiprint() works exactly like print(), but first runs parse() on all arguments.
ansiprint("<b>bold</b>", "<d>dim</d>")
ansiprint("<b>bold</b>", "<d>dim</d>", sep=":", file=sys.stderr)
颜色和样式
# Colors may be specified in one of several ways.
parse("<red>red foreground</red>")
parse("<RED>red background</RED>")
parse("<fg red>red foreground</fg red>")
parse("<bg red>red background</bg red>")
# Xterm, hex and rgb colors are accepted by the <fg> and <bg> tags.
parse("<fg 86>aquamarine foreground</fg 86>")
parse("<bg #00005f>dark blue background</bg #00005f>")
parse("<fg 0,95,0>dark green foreground</fg 0,95,0>")
# Tags may be nested.
parse("<r><Y>red text on a yellow foreground</Y></r>")
# The above may be more concisely written as:
parse("<r,y>red text on a yellow background</r,y>")
# This shorthand also supports style tags.
parse("<b,r,y>bold red text on a yellow background</b,r,y>")
parse("<b,r,>bold red text</b,r,>")
parse("<b,,y>bold regular text on a yellow background</b,,y>")
# Unrecognized tags are left as-is.
parse("<b><element1></element1></b>")
有关标记标签的列表,请参阅tags.py。
用户定义的标签
可以通过创建一个新的AnsiMarkup
实例来定义自定义标签或现有标签的覆盖
from ansimarkup import AnsiMarkup, parse
user_tags = {
# Add a new tag (e.g. we want <info> to expand to "<bold><green>").
"info": parse("<b><g>")
# The ansi escape sequence can be used directly.
"info": "e\x1b[32m\x1b[1m",
# Tag names may also be callables.
"err": lambda: parse("<r>")
# Colors may also be given convenient tag names.
"orange": parse("<fg #d78700>"),
# User-defined tags always take precedence over existing tags.
"bold": parse("<dim>")
}
am = AnsiMarkup(tags=user_tags)
am.parse("<info>bold green</info>")
am.ansiprint("<err>red</err>")
# Calling the instance is equivalent to calling its parse method.
am("<b>bold</b>") == am.parse("<b>bold</b>")
对齐和长度
对齐格式化的字符串可能具有挑战性,因为渲染的字符串长度与可打印字符数不同。考虑以下示例
>>> a = '| {:30} |'.format('abc')
>>> b = '| {:30} |'.format(parse('<b>abc</b>'))
>>> print(a, b, sep='\n')
| abc |
| abc |
可以使用ansistring
函数或AnsiMarkup.string(markup)
方法来解决这个问题,它具有以下有用的属性
>>> s = ansistring('<b>abc</b>')
>>> print(repr(s), '->', s)
<b>abc</b> -> abc # abc is printed in bold
>>> len(s), len(am.parse('<b>abc</b>'), s.delta
3, 11, 8
借助delta
属性,可以轻松对齐上述示例中的字符串
>>> s = ansistring('<b>abc</b>')
>>> a = '| {:{width}} |'.format('abc', width=30)
>>> b = '| {:{width}} |'.format(s, width=(30 + s.delta))
>>> print(a, b, sep='\n')
| abc |
| abc |
转义原始字符串
ansiprint()
和parse()
都会原样传递类型为raw
的参数。
>>> from ansimarkup import ansiprint, parse, raw
>>> ansiprint("<b><r>", raw("<l type='V'>2.0</l>"), "</r></b>")
<l type='V'>2.0</l> # printed in bold red (note the leading space caused)
>>> s = parse("<b><r>", raw("<l type='V'>2.0</l>"), "</r></b>")
>>> print(s)
<l type='V'>2.0</l> # printed in bold red
构建模板字符串也可能足够
>>> from ansimarkup import parse
>>> s = parse("<b><r>%s</r></b>")
>>> print(s % "<l type='V'>2.0</l>")
<l type='V'>2.0</l> # printed in bold red
其他功能
可以通过将tag_sep
参数传递给AnsiMarkup
来更改默认的标签分隔符
from ansimarkup import AnsiMarkup
am = AnsiMarkup(tag_sep="{}")
am.parse("{b}{r}bold red{/b}{/r}")
可以使用strip()
方法删除标记标签
from ansimarkup import AnsiMarkup
am = AnsiMarkup()
am.strip("<b><r>bold red</b></r>")
strict
选项指示解析器在开标签没有相应的闭标签时引发MismatchedTag
from ansimarkup import AnsiMarkup
am = AnsiMarkup(strict=True)
am.parse("<r><b>bold red")
# ansimarkup.MismatchedTag: opening tag "<r>" has no corresponding closing tag
命令行
Ansimarkup 还可以在命令行中使用。这相当于将所有参数都传递给了 ansiprint()
$ python -m ansimarkup
Usage: python -m ansimarkup [<arg> [<arg> ...]]
Example usage:
python -m ansimarkup '<b>Bold</b>' '<r>Red</r>'
python -m ansimarkup '<b><r>Bold Red</r></b>'
python -m ansimarkup < input-with-markup.txt
echo '<b>Bold</b>' | python -m ansimarkup
日志格式化器
Ansimarkup 还附带了一个用于标准库 logging
模块的格式化器。它可以这样使用
import logging
from ansimarkup.logformatter import AnsiMarkupFormatter
log = logging.getLogger()
hdl = logging.StreamHandler()
fmt = AnsiMarkupFormatter()
hdl.setFormatter(fmt)
log.addHandler(hdl)
log.info("<b>bold text</b>")
Windows
Ansimarkup 在内部使用 colorama 库,这意味着通过先运行
import colorama
colorama.init()
有关 Windows 支持的更多信息,请参阅 colorama 文档中的“使用”部分。
性能
虽然 Ansimarkup 的重点是方便,但它确实试图将处理降到最低。benchmark.py 脚本试图对不同的 ansi 转义代码库进行基准测试
Benchmark 1: <r><b>red bold</b></r>
colorama 0.1959 μs
colr 1.8022 μs
ansimarkup 3.1681 μs
termcolor 5.3734 μs
rich 9.0673 μs
pastel 10.7440 μs
plumbum 14.0620 μs
Benchmark 2: <r><b>red bold</b>red</r><b>bold</b>
colorama 0.5360 μs
colr 4.5575 μs
ansimarkup 4.5727 μs
termcolor 15.8462 μs
rich 21.2631 μs
pastel 22.9391 μs
plumbum 33.1179 μs
限制
Ansimarkup 是围绕 colorama 的一个简单包装器。它在验证标记字符串是否正确形成方面做得很少。这是一个有意识的决策,目的是保持简单和快速。
不匹配的嵌套,如下例所示,将产生不正确的输出
<r><Y>1</r>2</Y>
待办事项
- 许多角落案例仍需修复。
- 更详细的测试。当前的测试套件主要覆盖“快乐路径”。
- 在
sub_end
中用更有效的方法替换tag_list.index
(例如,类似于有序的 MultiDict)。
类似库
- pastel:为您的终端带来颜色
- plumbum.colors:适用于类似 shell 脚本的 Python 程序的小型但功能丰富的库
- colr:简单终端颜色,具有链式方法
- rich:在终端中进行丰富文本和美观格式化(请参阅
rich.print()
和rich.markup.render()
)
许可证
Ansimarkup 在 修订版 BSD 许可证 的条款下发布。
项目详情
下载文件
下载您平台上的文件。如果您不确定要选择哪一个,请了解有关 安装软件包 的更多信息。