tn是desert和tan共同开发的一种用于匹配,转写和抽取文本的语言。解释器使用Python实现,代码不超过1000行。

本文主要介绍tn的基本语法。高级内容可以参考其他篇章。使用这样的语法,是为了实现语言无关,从而方便地编写不同语言的解释器。

基本语法

引擎可以由一组规则构成,规则也可以被其他规则所组合。首先介绍最基本的元规则 。

1. 字符串StringEntity

Form2: ("Matched string" : "Rewritten string")

Form1是一种省略表达,即Rewritten==Matched

样例:

("" : " ") # 在指定的地方插入一个空格
("kg" : "kilogram") # 将 "kg" 或 "Kg" 扩展成 "kilogram"

2. 正则表达式RegexEntity

Form1: (/Matched expression/)
Form2: (/Matched expression/ : /Rewritten expression/)

样例:

(/\s+/ : / /) \#将一串连续的空格与换行符合并为一个空格
(/(\d+)\s?(-|~)\s?(\d+)/ : /$1 to $3/) #将 "15~20 dollars" 改写成 "15 to 20 dollars"

将用Matched匹配到字符串替换成Rewritten所表示的字符串。这里的正则表达式符合Perl正则规范。Form1只能作为匹配规则而不能作为转写规则,如果Rewritten为空,则只匹配不转写。Rewritten并不是真正的正则表达式,它仅支持普通字符串与$1, $2, ..., $99,$n 表示Matched expression匹配到的第n个Entity。

3. 脚本表达式 ScriptEntity

可以在文法中嵌入脚本,具体的语法规则由引擎所决定,目前可以嵌入Python。(详情可参考高级语法)


其他各类表达式,都是由这三类表达式进行组合得到的。它们的并(或操作),连接和差操作,构成了以下三类复合实体。这三种操作与正则表达式的三类基本操作一致。

表达式需要被其他表达式引用时,就需要为其命名,例如:

entity= (/\s+/ : / /) ;

这样就表达了一个名称为entity的字符串表达式。名称与c语言的变量命名规则一致。中间由=连接。最后由分号结束。

当引用其他表达式时,可以用$(RuleName)表达。


4. 或表达式 TableEntity

Form: Table_name =Entity1 | Entity2 | …

样例:

digit_0_to_9 = ("0" : "nol") | ("1" : "satu") | ("2" : "dua") | ("3" : "tiga") | ("4" : "empat") | ("5" : "lima") | ("6" : "enam") | ("7" : "tujuh") | ("8" : "delapan") | ("9" : "sembilan"); #印尼语数字 0~9 的Map 表
integer_int_extend = $(integer_int) | ("百" : "100") | ("千" : "1000") | ("万" : "10000") | ("亿" : "100000000");

integer_int_extend规则就是由integer_int和其他四个StringEntity构成的。

或表达式中间的分隔符有两种,竖线|和斜杠/。 以竖线分割的实体是平级的,会对每一个子表达式进行匹配,找出离字符串起始位置最近且匹配到的字符串最长的那个子表达式。而以斜杠分割的实体,被看做一组(Group),一旦匹配,就不会匹配之后的表达式。可以在表达式中指定多个组合平级实体。

看下面的例子:

grouptest= (/CD/) | (/ABC/) / (/AB/) | (/ABCD/);

该规则分成了两组,在匹配ABCD时,前一组已经匹配了ABC,因此就不会继续向后匹配到ABCD。因此该规则最终匹配的结果是ABC.

5. 序列表达式 SequenceEntity

序列表达式描述了表达式的连接。序列从左到右依次匹配,一旦出现不能匹配的情况,则整个序列匹配失败。注意,序列匹配的字符串必须是相邻的。

integer_0_to_99 = $(integer_0_to_9) | $(integer_teens)
| $(integer_decades) $(del_0)
| $(integer_decades) $(ins_space) $(integer_1_to_9) $(ins_space);

这个表达式实际上是一个TableEntity,后两个子表达式是SequenceEntity。该表达式可以转写0~99范围内的整数。

匹配211时它首先用第一个integer_0_to_9能匹配到 '2',再用第二个integer_teens能匹配到 "11",再用第三个表达式匹配失败,再用第四个Sequence能匹配到 "21",最终选择离起点最近且匹配到的字符串最长的那一个进行转写:

211 :twenty one

序列表达式可以完成转写和顺序调整。例如:

fraction = $(integer_int_extend) $(fraction_cnv_slash) $(integer_int) : $3 $2 $1

三分之一转写为1/3,integer_int_extend可以匹配‘三’, fraction_cnv_slash可匹配 '分之' , integer_int可匹配'一'。 $3 $2 $1 对其顺序进行了重排。

6.重复表达式RepeatEntity

Form1: Repetition_name = $(an_entity)+;
Form2: Repetition_name = $(an_entity){m,n};

由一条需要重复的规则、要重复的次数以及结尾的分号组成。需要重复的规则有且仅有一条。所以不能写成

error_example= $(an_entity0) $(an_entity){m,n};

m到n次,m是≥0的整数,n是≥0的整数或-1,为-1时表示不限制重复次数。

这与正则表达式的规则基本一致。

7.差集表达式DiffEntity

Form1: Difference_name = $(Universe) - $(complement);
Form2: Difference_name = $(Universe) - $(complement1) - $(complement2) - …;

由一组Complement以及结尾的分号组成。有且仅有一个Universe,后面用减号可以跟多个表达式。

当Universe表达式能匹配且其他complement不能匹配时成立。例如:

integer_1_to_9 = $(integer_0_to_9) - ("0" : "nol"); # 整数1~9
integer_2_to_999 = $(integer_0_to_999) - $(digit_1) - $(digit_0); # 整数2~999

8. 元标签

可以为表达式增加标签,控制表达式的属性和功能。也可以引入规则等。

文件级元标签:

文件级元标签,不需要贴在任何规则之上。

#%Include% Rules/cnext

增加一个名称为cnext的外置文件。本文件中的规则即可引用该文件中的规则。支持双向引用。

#%Script% extends

增加一个名称为extends.py的外置Python脚本。该标签适合在嵌入Python代码时使用。嵌入的代码可以执行外置脚本中定义的函数。引擎会在内部执行import(extends)函数。因此extends.py需要放置在规则文件同一级目录中。

规则级元标签:

规则级元标签需要放在规则文本行之上,如:

#%Type% INT
#%Order% 180
int_0_4= $(int_0) | $(int_1) | $(int_2) | ("三" : "3") | ("四" : "4") ;

上面的两个标签意思分别为:

将int_0_4的类型标记为INT

将int_0_4的匹配优先级定义为140. 数字越大,优先级越低。

不是所有的规则都是有效规则,有些规则只是被其他规则引用。只有加上#%Order%标签的才是有效规则。规则可以手动编写优先级。也可以省略之后的数字,引擎会自动根据引用结构来制定优先级,被引用层级越高的优先级越高。

#%Parameter% 为规则赋值

这部分取决于引擎的设计,将在《高级话题》中描述。

属性级元标签

在信息抽取时,属性元标签非常重要,它指定了引擎如何将文本转换为字典。

案例1

#%Property% Denominator,,Numerator| Numerator ,, Denominator | Denominator ,, Numerator
fraction = $(integer_int_extend) $(fraction_cnv_slash) $(integer_int) : $3 $2 $1 | $(integer_int) $(fraction2) $(integer_int) | $(pure_decimal) ("" : "/") $(percent_transform);

属性标签为fraction的每一个引用实体增加了属性。 按照 '|' 分组,Denominator赋给integer_int_extend, Numerator赋给integer_int. 分别代表分子和分母。

案例2

当抽取类似JSON或XML的文本时,抽取的字典需要以键值对的形式标注,如下例子:

#%Property% ,$key,,$value
properties =$(space) $(name) $(equal) $(property) $(space);

则在抽取时,会以name为键,property为value, 插入抽取的字典中。


9.注意事项

注释

除了符合元标签格式的文本,以 # 开始的一行内容被认为是注释行被忽略。暂不支持在一行内容的中间或后面加注释,也不支持在某一规则的多行内容的中间插入一行注释。

换行

当Rule内容特别长时可以直接换行,中间插入的换行符/空格/制表符会被忽略,但不支持在中间插入注释行。

结束符

所有Rules都要以分号结束。

交叉引用

规则可以支持交叉引用,甚至可以引用自身,但被引用的表达式需要存在,否则会引发错误。引用时,需要保证文法不是左递归的,否则将会陷入死循环。

编码

由于文本处理引擎经常处理多国语言,因而要求使用UTF-8编码(no BOM)。

tn文本分析语言(二) 基本语法的更多相关文章

  1. tn文本分析语言(三):高级语法

    标签(空格分隔): 未分类 高级操作 1.脚本表达式 用双引号包含的脚本被称为脚本表达式,目前支持嵌入Python. 脚本表达式只能在顺序表达式中使用.代码可以在三个位置存在: |位置|功能|例子| ...

  2. 重磅开源:TN文本分析语言

    tn是desert(沙漠之鹰)和tan共同开发的一种用于匹配,转写和抽取文本的语言(DSL).并为其开发和优化了专用的编译器.基于递归下降方法和正则表达式,能解析自然文本并转换为树和字典,识别时间,地 ...

  3. tn文本分析语言(四) 实现自然语言计算器

    tn是desert和tan共同开发的一种用于匹配,转写和抽取文本的语言.解释器使用Python实现,代码不超过1000行. github地址:https://github.com/ferventdes ...

  4. NetAnalyzer笔记 之 十一 打造自己的协议分析语言(1)初衷与语法构想

    回头看看NetAnalyzer开发系文档上次一篇竟然是2016年,老脸一红.不过这几年墨云成功过的讨到一个温柔贤淑的老婆,有了一个幸福的家庭,去年9月又有了一个大胖儿子,想想也就释然了^_^ 其实这几 ...

  5. [Markdown]纯文本标记语言MarkdowPad2--MD语法知识

    ##1.标题 代码 注:# 后面保持空格 # h1 ## h2 ### h3 #### h4 ##### h5 ###### h6 ####### h7 // 错误代码 ######## h8 // ...

  6. linux 文本分析工具---awk命令(7/1)

    awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各 ...

  7. Solr:文本分析

    文本分析时搜索引擎的核心工作之一,对文本包含许多处理步骤,比如:分词.大写转小写.词干化.同义词转化等.简单的说,文本分析就说将一个文本字段的值转为一个一个的token,然后被保存到Lucene的索引 ...

  8. C语言-01-基本语法

    一.学前需知 开发工具 windows平台:Visual C++6.0等 mac平台:Xcode6.0等 以下文章内容皆是以Xcode6.0为开发工具,clang编译器. Xcode的一些常用快捷键 ...

  9. 用R进行文本分析初探——以《红楼梦》为例

    一.写在前面的话~ 刚吃饭的时候同学问我,你为什么要用R做文本分析,你不是应该用R建模么,在我和她解释了一会儿后,她嘱咐我好好写这篇博文,嗯为了娟儿同学,细细说一会儿文本分析. 文本数据挖掘(Text ...

随机推荐

  1. 基于shell脚本比较数字加减乘除

    让用户输入两个数来比较他们的大小 先用touch命令新建一个2.sh文件 在用vi进入i进入编辑状态 输入 保存后检查

  2. FastDateFormat

    1 public static final FastDateFormat ISO_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd&q ...

  3. 39个让你受益的HTML5教程

    1. 五分钟入门HTML5 (Learn HTML5 in 5 Minutes!) By Jennifer Marsman 毫无疑问,HTML5是一个热门话题.如果你需要一个迅速了解HTML基础的速成 ...

  4. 使用复合设计模式扩展持久化的CURD,Select能力

    大家可能会经常遇到接口需要经常增加新的方法和实现,可是我们原则上是不建议平凡的增加修改删除接口方法,熟不知这样使用接口是不是正确的接口用法,比如我见到很多的项目分层都是IDAL,DAL,IBLL,BL ...

  5. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

  6. iOS程序模块化设计

    一.模块化设计的概述: 模块化设计(Block-based design):对一定范围内的不同功能或相同功能的不同性能.不同规格的产品进行功能分析的基础上,划分并设计出一系列功能模块,通过模块的选择和 ...

  7. 编译链接 C++

    预处理之后的源文件被称为一个编译单位,也即编译器的工作对象.为了使编译能够进行,程序员必须提供各种程序其他部分的声明来孤立分析一个编译单位.所有名字空间,类,函数都应该在他们所在的编译单位中有声明,所 ...

  8. Filter 数组过滤函数精解示例

    '************************************************************************* '**模 块 名:Filter 数组过滤函数精解示 ...

  9. Android动画

    [浅谈Android动画] 总共四种:Tween Animation变换动画.Frame Animation帧动画 Layout Animation布局动画.Property Animation 属性 ...

  10. PostgreSQL 杂志

    pgmag 团队刚发布了头两期 PostgreSQL 杂志,还有中文版http://pgmag.org/download,推荐广大 PostgreSQL 数据库管理员及开发者阅读: Issue #01 ...