汉字组字机制(笔画组字原理)

 

    我已写过两篇关于笔画组字原理的文章,不过都很简单,因为当时经验有限,理论也没有发展成熟。现在,我的经验和理论都有所提高,同时已有个别网友也想实现笔画组字的理想,我应该把我已有的有关知识全部写出来,尽量使别人容易看懂,以便共同使用,共同研究。本文就是为了这个目的,全面地简述我实现笔画自动组字的理论,它也可以作为使用我的小字库WORD软件,进行组字输入时的参考。

一:汉字组织的三个层次

1、笔画:25对,共50种,如下图所示(右边为该行各笔画相应的代码):

2、字根:2001000左右,组字用的要多,因为笔画有点变异就要另算一种。我现在用的936个如下图,毎100个一组,左上角注明组号,加上在组中的序号00-99,就是引用它们的字根号。如果能把它们归并为256类以下,则可用一个字节表示其类。用类码组字,当然要研制出组字软件,用条件语句正确选择使用类中那一个字根,这样就可用字根(类)码作内码,更利于输入、排序和检索。

3、汉字:2万到13万,常用字仅5000左右。

一般情况,先由笔画组成字根,再由字根组成汉字。许多字根可以独立成字,称为独体字,个别笔画也可以成字,如“一、乙”等单笔字。合体字与独体字、字根一样,也可成为更复杂的汉字之组成部分,可称为“子字”,作用与字根一样。汉字中也可以有没参与字根组织的孤立笔画,也同样可看作是“子字”或字根。复杂的字根中可含有别的字根,或可称为“子字根”,其作用将被看作与单一的笔画一样。

二:笔画及其参数

每个笔画有名称和代码、两个参数和两条曲线:

代码:50种笔画可用AY的大小写字母代表,小写代表主笔,大写代表副笔,一对主副笔大多形状相似,甚至可相互代替,如主笔“点”的代码为a,副笔“竖点”的代码为A(见第一幅图第一和第二个笔画)。

两个参数:横向线数x和竖向线数y分别表示两个方向的延展程度,在组字时用来计算笔画的相对大小。目前,它的绝对值大小关系不大,为了运算简单,尽量采用最小的数,故最大值取3,最小值取1。例如笔画横bx值为3,短横Bx值为2,它们的y值都为1

两条曲线:在笔画起落笔及转折处,都设一个骨干点。骨干点组成的骨干线是折线,在不同汉字中是要随笔画所占的空间的不同而变形的,即可能拉长或压扁。真正的笔画轮廓线,是平滑曲线(可采用贝式尔内插),由于轮廓线的关键点相对于与它最近的骨干点的相对距离是永远不变的,所以不论汉字中笔画多少,笔画所处位置不同引起拉长或压缩,都能保证笔画的粗细和转角形态完全一致。如图所示。

采用贝式尔内插计算平滑的轮廓线时,控制点的选择是关键,要试验是否适合各种压缩情况。组字都要先画轮廓线再填充,想必会降低速度。所以在编研小字库WORD时,我直接使用从字库字拷贝来的字形(前面引用的笔画和字根两张图,都是这样拷贝来的)。我没有具体测试两者速度数据有什么不同,单凭两种软件运行时的感觉来看,差别是不大的。对于结构简单的、其组成部分笔画数相差不多的汉字,用拷贝组出的字形较好。否则,由于拷贝压缩程度不同,笔画粗细不一样,字形就难看了。例如小字库WORD软件中举的Biangbiang面的biang字, “走之”内包围的笔画太多,经压缩后笔画很细了,但走之却很粗,我虽然有意将后者瘦了一些,仍不协调。

三:笔画串层积理论

  由笔画串组出字根的层积理论 :在独体字根中,一般笔画是按笔顺上下叠加的,一个笔画构成一个“层”,层高等于其线数y。如果某笔画与前一笔画相交,就把它看成是从下层延伸到上面的层,要向上延伸n线数,就在该笔画后面加上一个数字n。例如,短横B、长横b加上长竖c再加数字1Bbc1),就会组成“干”字。这整个字的纵向线数,是两个横的1,加上一个竖的3,共计5,程序按这总线数分配空间,两个横只占上部2/5弱,而竖笔的y向线度3则在横笔下面,另在长横之上延伸线度1,故显得头重脚轻。为此在长短横间插入2个空笔z2z后的数字表示有几个空笔或该空笔占多少线数),变成Bz2bc3,则竖在长横上下都一样长,就好看了。

如果数字n前加一个*号,则表示它占据的是从上一层笔画的底部向上延n个线数,即它自己没有独立的层,整个字也不增加线数,完全是重叠的笔画。如Bzc*1b,它是个“工”字。竖笔c虽然原有纵向线数3,但它没有自己的空间,只在空笔z的空间里延伸1个线度。

笔画组成左右结构的情况很少,这时必须放在方括号[ ]之内,它们只形成一个层。这个层内的诸笔画,后面可加数字n而向上延伸n线数,如果加+ n,则向左延伸n线数。如果该层第一个笔画加*n,则整层将有同样的高度n,而且都是从上一层底部开始向上延伸,没有自己独立的空间,完全是一个重叠的层。笔画没有向上延伸不同高度时的左右结构层(包括重叠层),其中的笔画将有同一个高度,即有相同的y线数,数字等于其中y线数最大者,线数较小的笔画自动伸长。

同样,同一个字根或子字中,所有层的横向线数也是相同的。如果有一个层是左右结构的,随着该层中笔画的增加,横向线数必然增加,那么其他所有层的横向线数都增加到相同的数值。例如zbz[c*3c]是“艹”的笔画序列,横向线数是横b3,因为竖c的横向线数是1,层[c*3c]的横向线数本为2,也增为3了。而zbz[c*3ccc]是汉字“卌”,横向线数等于层[c*3ccc]4,横b的线数也增为4。但是线数只用来安排笔画的相对位置的。上面举的两个字的横b,虽然有不同的横向线数,但有同一个长度,它们都占一个字的宽度。

笔画结构序列是表示一个字根的,该序列中也可以包含、即调用别的字根以至汉字。被调用的字根可称为子字根,是被当作一个普通笔画来看待的,这个特殊笔画具有的线数,就是该字根的总线数。子字根有自己的笔画结构序列,按原有的规律组成字形,只不过它被安置在母字根的一定位置中,实际上已被压缩。如果把一部分笔画用大括号{}括起来,也称为子字根,也当作一个笔画看待。圆括号()内的笔画也是一个子字根,不过它有一点特殊作用,这个子字根要写到前一笔画(例如折弯钩、弯钩)的左下方,而且前一笔画的线数会随子字线数的增加而增加。圆括号的作用不仅使弯钩包容的东西可多可少,也保证了弯钩先写的笔顺。同样为了使“小”字的竖钩先写,可把左边的点用圆括号括起来放在竖钩后面。

四:字根及其参数

字根也被称作部件、字元等,它们是研究汉字字形输入法时“拆分”出来的。笔画组字用的字根,必须是不与其他部分相交的,最多是相接,即只能是“切分”出来的。每个字根由以下特性规定之:

1、笔画串:由该串能组出该字根。注意,在不同的字根里有些笔画要变异。“木”作左偏旁时,第四笔捺要变为点;“翅14”(“翅”字第一到第四笔)其笔画组成“支”完全一样,但末笔捺要拖长。我们已指出,现在笔画变异后是要算不同字根的。

2、笔画数和总线数:xy总线数,分别为各笔画的xy线数之和。

3、结构码:用一个3位整数规定与其他字根的相互关系:

1)左右结构类:结构码百位数为0,绝大部分末两位也为0。因为每个字根应占多少空间,开始时单纯由该字根笔画数计算的,在笔画数很多的汉字中,一些笔划很少的偏旁所占的位置就太窄小。当时用结构码的后两位数来规定扩大它应占空间的倍数。实际上这个方法不好,当另一半笔画也少的个别汉字里,它又占得太大了。所以应该使用线数来计算各部分应占的空间。

2)上下结构类:结构码百位数为1,一般为100。有些字根底部中空,如“宀”等,希望后续字根能升高写入其中空部分,末两位数用来规定后续笔画升到该字根内部的百分数。

3)嵌套结构类:结构码百位数大于1,其后续笔画写入其内部。后续笔画占据的空间之边缘,离开嵌套字根边缘各有不同的距离。一般来说,如果上下两端或左右两边都有距离的话,是相等的。所以只要用一个数N(十位数)指定x方向离开十分之几,用一个个位数M指定y方向离开十分之几。而结构码是百位数L(整个结构码为LNM),它用来指明嵌套种类时,也就指明了到底那几个方向是离开嵌套字根的边缘的,这些百位数分别是:

                                     i.              左上包围(L=2):如“厥”字之“厂”、“扇”字之“户”等,左边离开N/10,上边离开M/10

                                  ii.              右上包围(L=3):如“匍”字之“勹” 、“司”字之“”等,右边离开N/10,上边离开M/10

                               iii.              上三包围(L=4):如“问”字之“门”、“同”字之“冂”等,左右都离开N/10,上边离开M/10

                                iv.              左三包围(L=5):如“医”字之“匚”、“匡”字之“匚”等,左边离开N/10,上下都离开M/10

                                   v.              下三包围(L=6):如“函”字之“凵”、“幽”字之“山”等,左右都离开N/10,下边离开M/10

                                vi.              左下包围(L=7):如“毯”字之“毛”、“翅”字之“支”等,左边离开N/10,下边离开M/10

                             vii.              走之包围(L=8):如“连”字之“辶”、“建”字之“廴”等,数据同f,但嵌套字根是最后写的。

                          viii.              全包围(L=9):如“国”字之“囗”,“周”字之外框也可列入此类,左右都离开N/10,上下也都离开M/10

注:走之包围(L=8)原来是属于左下包围(L=7)的,这样要先写走之,再写被包围的右上部分,不符合书写的笔顺。把它独立出来,只要把被包围的右上部分用圆括号括起来,就可移到前面,就符合笔顺要求了。但是,全包围之“囗”字,前两笔先写,最后才用一横封口,无论如何不能符合笔顺要求,若不改变原有计算笔顺的习惯,就要在由字根计算笔画排序时使用特别的程序。

另外,嵌套结构用结构码后两位数来固定预留嵌套部分的空间,也不很合理,所以调整并规定每个字根的这些参数不大容易,实际上改用线数来计算就比较灵活而且简单。

五:字根串如何组成汉字

规定了各字根的结构码和笔画数等参数后,使用相应的程序,字根串就可自动组成汉字,所以它也可当作该汉字的内码。字根串中可以直接调用汉字内码,它可还原为用圆括号括起来的字根串,两者都被看作是一个子字,缺省的结构特性是左右结构。非上下结构的字根和子字如果要改为上下结构,可在后面加结构符“:”,而强迫字根改为左右结构的结构符是“”。强迫改为包围结构的结构符是“=”,它是全包围结构符,不需要其他包围结构符,后面也可以附加数字。如果要在汉字上叠加对号∨、错号×、或加圈○时,就要用到这种包围结构。

组成汉字的字根序列里是可以直接出现笔画序列的,程序会分辨出笔画序列,先组成临时的字根,其缺省的结构特性也是左右结构,即每一段笔画串将被当作一个左右结构的字根。不过在这些笔画串中间就不可以使用有特殊作用的表示子字根的圆括号,因为在表示汉字的字根序列里,圆括号已用来表示子字。如果这些笔画组成的子字与后面的成分是上下结构的,就要用圆括号括起来,后面发一个冒号。

在我最近编研的小字库WORD中,同时可以使用字库字和合成字。第一版本之后,就可以在合成字中直接调用字库字,这可能是最常用而最有意义的部分。但参与组字的成分,是必须有各种参数的,字库字显然都没有。结构参数可取缺省的左右结构,个别上下结构的则加冒号。没有笔画数和线数,就不能计算出适当的占有空间。简单的组成部分大小相似的可等量分配,效果还不错。对于各组分差异大的,各子字后面就都要加附加一个数,以便按比例分配空间。