汉文博士词典编译配置文件概述
概述
《汉文博士》允许使用者自己编写词典文件。本文简要讲述了词典编译过程和相关配置文件的编写方法。
词典编译器
《汉文博士》的词典编译器可在“文件”菜单中点击“词典编译器”调出。
编译前,需点击“加载”按钮指定配置文件。选定配置文件后,将自动填写输出位置。点击编译按钮后,将编译词典,并自动注册到程序的词典库,供后续检索。
编译配置文件概述
词典编译配置文件是一个XML文件,程序使用配置文件中定义的正则表达式处理指定的文本文件,将文本内容转换词典内容。
提示:程序下载空间的词典源文件目录下,有大量的示例可供参考。
编译配置文件至少应包含如下几类信息:
- 词典的基础信息,如名称(title)、版本(version)、出版社(publisher)、制作人(creator)、简单说明(description)等
- 词典的字段(fields),例如:读音、出处、解释、例句等,全部都可自由定义。
- 一个词典数据库至少要有一个字段(field)。
- 字段需要指定名称(name)和说明(description)。
- 默认的字段数据类型(valueType)是纯文本。
- 标记类型表示字段内容为HTML。
- 此外还有其他类型,如拼音、粤拼、相关汉字列表等等。
- 字段的内容,在显示成检索结果前,可以指定正则表达式模式(pattern),将字段文本替换(replace)成其它内容(replacement,例如HTML标签、跳转连接等)。因此,不需要在源文件里插入大量的HTML标签,在运行的时候可以转换,从而使词典能压缩得再小一些。
- 词典的数据(data)源文件。
- 词典的源文件(file)是文本文件,编译器逐行(row)读取文本文件,根据正则表达式(pattern),提取出词条(word),将其它文本则映射到相应的字段(field)。
- 一部词典可以有不止一个源文件。
- 词条可以重复。检索词条时,程序会将词典中匹配该词条的所有内容,按源文件中的出现顺序,依次显示出来。
- 源文件(encoding)建议使用UTF-8或GB18030编码,以最大限度地支持可以显示的汉字。
- 在编译写入词典文件前时,可以对文本作替换(replace)。
- 一般不需要考虑词头的简繁体表示形式,程序可以在检索时自动简繁或异体通查。
- 一般也不需要考虑释义正文的简繁体表示形式,用户可以选中词典正文,在右键菜单中将内容转换成简体或繁体。
除了上面必备的信息之外,编译配置文件还支持如下高级特性:
- 词典文档(documentation)。“文档”是指不属于词典词条的辅助性内容,例如序、前言、凡例、附录等等,用户点击检索结果的词典标题,就会转到词典的基本信息页,在该页面可查看词典的“文档”。词典文档可以是文本文件、HTML网页或简易Markdown文件。
- 词典资源(resource)。“资源”是指不被此条件检索得到的数据内容,比较典型的就是插图,此外,对于不希望直接在词典文档列表中出现的内容,也可以放在资源内。
- 字段分类(category)。字段可以具有类别,在检索结果中显示。这个比较罕见,一般出现于结构比较复杂的词典。
- 字典。由于字典为单字,检索速度比词典快一些。如果要编辑的词典实际上是字典,或者包含大量单字,可以在配置文件中指定字典属性(enableCharacterDictionary),让编译出来的词典中使用字典结构来保存单字条目。
- 同义词(synonym)。编译器允许在配置文件中使用正则表达式为词头指定同义词。同义词和词头的检索结构都指向相同的释义内容。在词头行(word)或内容行(row)中都可以指定同义词。
编译示例
下文以《本草害利》为例,讲解词典的编译制作方法。源文件可在程序下载空间的词典源文件→本草害利目录下载。为方便起见,源文件被压缩成一个7zip文件包,下载后请将文件解压出来,然后在编译器中选择其中的“本草害利.xml”进行编译。
分析源文档结构
《本草害利》是清代凌奂编著的一部本草医书,书中收录了约三百种中药材,作者基于用药如用兵的思路,按脏腑和效能归类,划分成类似“心部药队〔补心猛将〕”、“肺部药队〔温肺猛将〕”等分类,并逐一讲解各药材的“害”、“利”和“修治”。在本示例中,我们将药材名称作为词头。例如中药材“五味子”的检索结果如下图所示:
源文件开头的部分内容大致如下图所示(未换行,已隐藏长行后面的文本)。
编译前的文档准备工作
为了编译成词典,我们对原始文件作过一些编辑。例如:
- 在药材名称前加了一个“★”号,在编译时,我们将指定“★”号后面的内容为词头。这种约定符号可以根据个人喜好而定,并没有特殊要求。
- 由于药材通常有别名,例如“北五味”又名“五味子”。原始文件在“北五味”后本来没有“、五味子”,如果不指定别名,输入“五味子”的时候就查不到这个条目的内容了,因此,我们在“★北五味”后面,增加“、五味子”,并指定“、”为同义词分隔符(synonymDelimiter)。
- 作者在讲解一味药材的时候,有时会提到其它药材。我们希望,在检索结果界面点击这些被提到的药材,可以跳转到对应的词条。例如上图的“干姜”也是一味药材,我们使用半角的中括号把它括起来,变成“[干姜]”,表示可以点击的词条连接。这种标记方式也是按个人喜好,我们在配置文件中指定即可。
- 文中有些地方使用了药材的简称,例如“(白芍)同归地补血”,这里“归”指当归,“地”指“地黄”,我们使用中括号加括号的方式表示这种关系,变成“同[归](当归)[地](地黄)补血”,在检索结果界面中显示的是“同归地补血”,而点击“归”字将检索“当归”,点击“地”字将检索“地黄”。
再观察一下文件,由于药材部队出现在药材名称之前,也就是词条标记“★”之前,因此,出现在“★北五味”前面的“心部药队〔补心猛将〕”将无法作为释义写入“北五味”词条,而出现在“★酸枣仁”前的“心部药队〔补心猛将〕”,将成为“北五味”的内容。虽然在这里没关系,因为内容是一样的,“北五味”也缺少药材部队的内容,但到后面切换药材部队的时候,就会错位,造成内容错误。为了补救,我们将根据“药队〔”先忽略掉这里出现的药材部队,另外再使用一个名叫“BowPad”的文本编辑器,通过正则表达式,提取出药材部队和药材的关系,制作了一个名为“本草害利目录.txt”的文件,内容大致如下所示,每行一种药材和药材部队的关系,中间用制表符分隔。编译时,我们将这个文件的内容放在前面先编译,而正文文件的内容放在后面编译,就能得到开头检索结果的效果。
北五味、五味子 心部药队〔补心猛将〕
酸枣仁 心部药队〔补心猛将〕
柏子仁 心部药队〔补心猛将〕
远志肉、远志 心部药队〔补心猛将〕
丹参 心部药队〔补心猛将〕
编译配置文件
下面是编译配置文件:
<?xml version="1.0" encoding="gbk"?> <config title="本草害利" author="清·凌奂"> <fields> <field name="category" cssClass="categoryTitle" description="部队" fieldNameVisible="no" mergeAdjacentField="true" adjacentFieldDelimiter="、"/> <field name="content" description="内容" valueType="标记" fieldNameVisible="no" fullText="yes"> <replace pattern="\[([^\]]+)\]\(([^\)]+)\)"> <replacement><![CDATA[<ref q="$2" title="$2">$1</ref>]]></replacement> </replace> <replace pattern="\[([^\]]+)\]" replacement="<ref>$1</ref>"/> <replace pattern="〔.+〕" replacement="<b>$0</b>"/> </field> </fields> <data file="本草害利目录.txt" encoding="GBK" synonymDelimiter="、"> <column field="1"/> </data> <data file="本草害利.txt" encoding="utf-8" synonymDelimiter="、" allowEmptyLine="true"> <word pattern="^★" removePattern="true"/> <row field="2"> <ignore pattern="药队〔" useRegex="false"/> <ignore pattern="(见" useRegex="false" /> <ignore pattern="(同上" useRegex="false" /> </row> </data> </config>
“config”元素中出现的“title”和“author”属性分别表示词典的名称和作者。这些将会显示在检索结果窗口上。
词典字段
“fields”元素下的“field”元素指定了两个字段。第一个字段将用来显示药材部队,第二个字段用于显示“害”、“利”、“修治”等正文。
第一个字段的代码如下:
<field name="category" cssClass="categoryTitle" description="部队" fieldNameVisible="no" mergeAdjacentField="true" adjacentFieldDelimiter="、"/>
从检索结果窗口可以明显看出,两个字段的显示效果是不一样的。原因是第一个“name="category"”的字段具有“cssClass="categoryTitle"”属性,表示使用类名为“categoryTitle”CSS样式。可以使用的样式,是在程序目录的style.css文件中定义的。程序默认会将字段描述名称(这里是“部队”)显示到检索结果,指定“fieldNameVisible="no"”可以隐藏字段名称。
由于一种药材可能同属于多个药材部队,例如“北五味、五味子”在上面的目录文件中一共出现了三次,因此,需要程序把它们串起来。我们可在配置中指定“mergeAdjacentField="true"”将相邻的相同字段结果串连起来,另外再指定“adjacentFieldDelimiter="、"”,使用逗号将内容分隔开。这样,就得到了开头截图里几个药材部队串连在一起的效果了。
第二个字段的内容较多,代码如下:
<field name="content" description="内容" valueType="标记" fieldNameVisible="no" fullText="yes"> <replace pattern="\[([^\]]+)\]\(([^\)]+)\)"> <replacement><![CDATA[<ref q="$2" title="$2">$1</ref>]]></replacement> </replace> <replace pattern="\[([^\]]+)\]" replacement="<ref>$1</ref>"/> <replace pattern="〔.+〕" replacement="<b>$0</b>"/> </field>
“valueType="标记"”属性表示这个字段的内容是HTML标记(如果不加这个属性,所有内容就会被视为纯文本,也就不会有跳转连接)。
“replace”元素指定了在显示检索结果之前对字段内容的替换操作。“pattern”属性的值是正则表达式,用于匹配文本,而“replacement”属性或元素的内容则表示替代的内容。其中“$1”、“$2”之类的标记表示正则表达式捕获的分组内容。
第一组替换表达式“\[([^\]]+)\]\(([^\)]+)\)”表示替换类似于前文提到的“同[归](当归)[地](地黄)补血”模式。“[归](当归)”将被替换成“<ref q="当归" title="当归">归</ref>”。“ref”元素在程序中有特别的含义,表示词条连接。其中“q”属性表示要检索的词条,“title”属性就是鼠标移上连接所显示的提示文字,“ref”元素的文本就是连接的内容。由于本组替换内容比较复杂,因此我们把它放在一个CDATA节中,避免为替换目标的引号和尖括号编写不直观的实体引用。
第二组替换表达式“\[([^\]]+)\]”表示替换类似于前文提到的“[干姜]”的模式。“[干姜]”将被替换成“<ref>干姜</ref>”。由于要检索的内容和要显示的内容是一样的,所以就不需要“q”属性了。
在安排替换顺序时,要注意先后,必须先替换掉方括号加圆括号的模式,再替换仅有方括号的模式,如果反过来,“[归](当归)”就会被“\[([^\]]+)\]”模式对应的替换组替换成“<ref>归</ref>(当归)”,而“\[([^\]]+)\]\(([^\)]+)\)”就得不到替换文本的机会了。
第三组替换表达式“〔.+〕”表示将“〔害〕”、“〔利〕”和“〔修治〕之类的内容替换成粗体。
数据源文件
字段元素后出现的“data”元素代表词典数据源文件。源文件是文本文件,一般有列布局和行布局。
- 如果文件使用列布局中,每行一条词头,使用制表符分列,第一列为词头,后面各列为字段数据。
- 大部分文件使用行布局,程序逐行读取文本,根据正则表达式确定每行数据对应词头还是字段。
第一个源文件对应的配置代码如下:
<data file="本草害利目录.txt" encoding="GBK" synonymDelimiter="、"> <column field="1"/> </data>
“encoding”表示该文本文件的文本编码,要注意必须与“file”属性对应文件的编码保持一致,否则就会无法读取。
“synonymDelimiter="、"”指定了词头的同义词分隔符。
注意“data”元素下出现的“column”子元素。这个元素表示这个文档是列布局(按制表符分列),其中第1列隐含表示词头,各个“column”元素表示后面的列,将对应字段内容。因此,这个“column”元素对应第二列,对应的“field="1"”属性表示该列对应前面定义的第1个“field”元素对应的字段(即药材部队)内容。
在本示例中,文件只有两列(大致如下所示),第一列对应的是词头,在“synonymDelimiter="、"”的作用下,诸如“北五味、五味子”的词头被拆分成“北五味”和“五味子”两个词头。第二列“心部药队〔补心猛将〕”对应药材部队字段。
北五味、五味子 | 心部药队〔补心猛将〕 |
酸枣仁 | 心部药队〔补心猛将〕 |
柏子仁 | 心部药队〔补心猛将〕 |
第二个源文件的代码如下:
<data file="本草害利.txt" encoding="utf-8" synonymDelimiter="、" allowEmptyLine="true"> <word pattern="^★" removePattern="true"/> <row field="2"> <ignore pattern="药队〔" useRegex="false"/> <ignore pattern="(见" useRegex="false" /> <ignore pattern="(同上" useRegex="false" /> </row> </data>
由于源文件有大量的空行。按程序的默认设置,空行被作为词条内容的结束标记,而本实例的文件并非如此。因此,我们可以指定“allowEmptyLine="true"”,允许空行出现在词条内容之中。编译器在编译时就会自动将空行忽略掉。
这里出现的“word”元素表示词头,“row”元素表示除词头外用于识别各行对应哪个字段的规则。
“word”元素的“pattern”属性表示行首以五角星开头的行被识别为词头。
由于五角星在这里已经被用来识别词头了,而它实际上并不是词条文本,只是我们为方便程序编译器识别词头而加的标记,因此要把它删掉。removePattern="true"属性,就表示删掉匹配“pattern”属性的内容,这样,行首的五角星就不会出现在词头了。
由于这个“data”元素也有一个“synonymDelimiter="、"”属性,因此,顿号也被用来分隔词头。
“row”元素的“field="2"”属性表示这个元素为第二个字段,即前面定义的“内容”字段定义规则。
由于文档中只有正文内容,没有其它内容了,所以不需要筛选。如果一个文档里有多个字段,可以在“row”元素里指定“pattern”属性,使用正则表达式匹配字段。
三个“ignore”元素在这里表示忽略匹配“pattern”属性内容的行,“useRegex="false"”属性表示“pattern”属性是普通文本,不是正则表达式。如果源文件某一行文本的内容包含这里三个“pattern”中的一个,都会被忽略。
在一个“row”元素内,也可以指定“replace”元素,在写入词典之前替换掉一些内容。
总结
本文讲解了词典编译的工具和配置文件的常见元素和属性设置,并以《本草害利》为例讲解了词典编译配置文件的编写方法。本文讲解的编译配置只是较基础的部分,还有更多的功能将在后续的文章讲解。
词典源文件的示例可在下载区下载 (访问密码: 8518)
从上述设计也可见,《汉文博士》的词典编译器支持多种文本文件布局,比较灵活。字段的概念为建构词典逻辑内容提供了方便。独特的运行时文本替换机制,使得词典源文件可以做得比较简洁,无需嵌入大量标签,也减小了词典文件的空间占用。而程序简繁异体通查和同义词机制便于词条检索,也使词典制作人员可以更专注于创作优质内容,不会被词典程序的功能限制所困扰。