用 Ascii 画关系图
写备注总有时候光靠文字描述不是很清楚,这个时候特别想在文档中附个关系图。用 graphviz 的 DOT 来描述图固然不错,但是它需要额外工具来生成才能直观的查看。如果我们想在纯文本环境附上插图,使用 ascii art 是最佳选择。
我搜了一下,perl 的 Graph::Easy 是唯一能找到的支持 ascii 输出的关系图绘制软件。
但是这个东西有个问题,就是对中文支持不行,虽然文档中说完全支持 Unicode ,但显然作者并没有把汉字用在 Ascii 输出上过。
问题是这样产生的:UTF8 中,汉字是 3 字节,而对于显示来说,等宽字体的汉字是 2 倍普通字母宽。这样在排版时,你必须知道一个字符串在视觉上是多宽,才可能用 ascii 字符拼接出正确的方框和连线。
比如,这个帖子就讨论了类似的问题 。
一开始,我希望找到 Graph::Easy 库中取 label 宽度的函数,让它正确返回 label 的视觉宽度。修改后,发现还是不行。这是因为,这个东西在 ascii 输出时,是用一个 2D 的字符数组模拟了虚拟画布(framebuffer)。它认为,framebuffer 上的一个矩形区域,就应该是 w * h 个字符构成的区域。如果想进一步的让它在 framebuffer 上定位正确,还需要修改它计算坐标的地方。可是,写 framebuffer 是一个随机过程,你向左边写一个一个字符,如果是汉字的话,会改变右边的 x 坐标。也就是把右侧所有的字符都挤了一个位置。如果再重排右侧的所有数据代价就太大了,而且它的内部模块也并没有抽象出这样的定位函数。
后来我想到一个取巧的做法,再读取任何 label 串时,都把这个串处理一下,把其中的汉字全部追加一个不可能在正常文本中存在的字符 U+FFFF ,让每个汉字都真的占据两个字符位。这样的字符串处理函数原本就在模块内存在(因为它本身就要去做类似 \n 的转义),这样就可以让整个排版过程正常了。
接下来要改的是最终把 framebuffer 序列化回字符串的过程,把里面所有的 U+FFFF 都删掉,就可以正确的输出了。
ps. 本来想提个 PR ,但是 github 上的那个仓库似乎不是原作者在维护的, CPAN 上的版本也不知道怎么提 issue ,所以还是自己玩玩就行了吧。
2017 年 5 月 2 日补充:
有同学找我要 patch ,我附在这里:基于 Graph-Easy 0.76 版。
diff --git a/lib/Graph/Easy.pm b/lib/Graph/Easy.pm index 0ae40fd..b67bacc 100644 --- a/lib/Graph/Easy.pm +++ b/lib/Graph/Easy.pm @@ -1570,7 +1570,9 @@ sub as_ascii # select 'ascii' characters $self->{_ascii_style} = 0; - $self->_as_ascii(@_); + my $asc = $self->_as_ascii(@_); + $asc =~ s/(\x{FFFF})//g; + $asc; } sub _as_ascii diff --git a/lib/Graph/Easy/Node.pm b/lib/Graph/Easy/Node.pm index b58f538..6d7d7c7 100644 --- a/lib/Graph/Easy/Node.pm +++ b/lib/Graph/Easy/Node.pm @@ -1503,6 +1503,9 @@ sub label $label = $self->_un_escape($label) if !$_[0] && $label =~ /\\[EGHNT]/; + # placeholder for han chars + $label =~ s/([\x{4E00}-\x{9FFF}])/$1\x{FFFF}/g; + $label; }
Comments
Posted by: ching | (11) August 20, 2021 06:59 PM
Posted by: tech | (10) May 5, 2017 03:28 PM
Posted by: Anonymous | (9) January 4, 2017 06:04 PM
Posted by: itfanr | (8) December 18, 2016 03:18 PM
Posted by: everding | (7) December 12, 2016 01:37 AM
Posted by: 陈钢 | (6) December 7, 2016 06:00 PM
Posted by: 大头龙仔 | (5) December 7, 2016 02:14 PM
Posted by: z | (4) December 7, 2016 11:53 AM
Posted by: pi1ot | (3) December 7, 2016 10:49 AM
Posted by: tench | (2) December 7, 2016 09:23 AM
Posted by: hawk | (1) December 7, 2016 08:19 AM