开源夏令营之foldcolumn工具及解决方案(三)表格列超长自动换行实现

来源:互联网 发布:网络白莲花是什么意思 编辑:程序博客网 时间:2024/06/15 22:12

常用自动换行算法

参见WIKI关于自动换行算法的介绍链接

自动换行是一个最优化问题,因不同的需求有不同的解决办法,下面是两种常用的算法。

最小长度

这种方法是实现自动换行的一个简单方法,属于贪心算法:尽可能多的单词放进一行里,直到所有的单词都已经放进去为止。这是很多现代文字处理软件的做法,如Microsoft Word和Open Office 。这个算法在追求最少行数的目标上能够达到最优化。下面是该算法的伪代码实现:

SpaceLeft = LineWidthfor each Word in Text  if Width(Word) > SpaceLeft    insert line break before Word in Text    SpaceLeft = LineWidth - Width(Word)  else    SpaceLeft = SpaceLeft - (Width(Word) + SpaceWidth)

LineWidth指一行的宽度,SpaceLeft指一行中剩余的空格,SpaceWidth是一个空格的宽度,Text是输入的文本,Word是文本中的一个单词。

注意:实现中,对于连续不能换行长度大于表格列宽的字符串(如长单词)直接从下一行开始输出。

最小破损度

在TeX中使用的,则是另一个算法,旨在将行尾空格数的平方最小化,以产生一个更加美观的结果。以上的最小长度算法不能完成这一目标,为了解决这个问题,我们需要定义一个惩罚函数c(i, j),用于计算包含单词Word[i]到单词Word[j]的一行的代价:


其中P通常为2或3。另外,有一些特殊的情况值得考虑:如果结果为负(即单词串不能全部放在一行里),惩罚函数需要反映跟踪或压缩文本以适应一行的代价;如果这是不可能的,则返回无穷大。最优解的代价可以用以下的递归式定义:


这种方法的时间与空间代价是值得考虑的:当利用动态规划来实现,时间和空间复杂度均为O(N^2)

foldcolumn自动换行实现

算法选择

foldcolumn采用上面的最小长度方法实现自动换行,而不采用最小破损度的方法,下面分析原因:

(1)从命令行管道等读入数据,不能提前读入数据,所以不适合最小破损度的方法;

(2)从文件读入数据时,可以使用最小破损度的方法,但是这种算法的复杂度不适合本项目,一是空间复杂度较高,二是需要多次读入数据来确定列宽。

算法实现

循环读入一行数据,按列分隔符分列,对每列循环使用最小长度算法进行输出,这里和上面的算法描述不同的是,不是按单词来处理,而是按连续不能断行的字符串来处理。其中借助libunibreak的liblinebreak库判读某个字符后面是否可以断行,liblinebreak的使用方法如下:

 liblinebreak/libunibreak提供了简单明了的函数接口,使我们能对Annex 14/29等不是很了解的情况下,能根据其返回信息,决定该如何换行、断单词。如使用时,先init初始化,再根据编码调用set_linebreaks_utf32(const utf32_t*s, size_t len, const char *lang, char *brks)等相应函数,获得一段数据的必须换行、允许换行、不可换行等信息并存储在brks,然后我们根据brks再结合实际需求选择某些可以断行位置实现断行输出。具体实现参见foldcolumn/libfoldcolumn/src/foldcolumn.c foco_dumpOneLineOfColumn函数。

效果展示

不包含连续不可断行的长字符串



包含连续不可断行的长字符串


参考

自动换行实现链接

libunibreak链接

0 0