栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

python使用textX构建属于自己的语言模型

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python使用textX构建属于自己的语言模型

系列文章目录
  1. python使用textX构建属于自己的语言模型
  2. python使用textx-model包

文章目录
  • 系列文章目录
  • 一、textX是什么?
  • 二、安装
  • 三、快速介绍
  • 四、定义一个可执行字符串表达式的模型
    • 1. 定义元模型
    • 2. 构建解析器
    • 3. 构建完成
    • 4. 使用构建的模型
  • textx-model介绍


一、textX是什么?

textX是一种元语言,用于在Python中构建领域特定语言(DSL)。它的灵感来自Xtext。

简而言之,textX将帮助您以一种简单的方式构建文本语言。您可以发明自己的语言,或者对现有的文本语言或文件格式建立支持。

textX将从单一语言描述(语法)为该语言构建一个解析器和一个元模型(也称为抽象语法)。有关详细信息,请参阅文档。

textX遵循Xtext的语法和语义,但在某些地方有所不同,并使用Arpeggio-PEG解析器在Python中100%实现——没有语法歧义、无限制的前瞻性、解释器风格。

github上的地址:https://github.com/textX/textX

二、安装

pip install textX

三、快速介绍

下面是一个完整的示例,展示了用于绘图的简单DSL的定义。我们还展示了如何定义自定义类、解释模型和搜索特定类型的实例。

代码如下(示例):

rom textx import metamodel_from_str, get_children_of_type

grammar = """
Model: commands*=DrawCommand;
DrawCommand: MoveCommand | ShapeCommand;
ShapeCommand: LineTo | Circle;
MoveCommand: MoveTo | MoveBy;
MoveTo: 'move' 'to' position=Point;
MoveBy: 'move' 'by' vector=Point;
Circle: 'circle' radius=INT;
LineTo: 'line' 'to' point=Point;
Point: x=INT ',' y=INT;
"""

# We will provide our class for Point.
# Classes for other rules will be dynamically generated.
class Point(object):
    def __init__(self, parent, x, y):
        self.parent = parent
        self.x = x
        self.y = y

    def __str__(self):
        return "{},{}".format(self.x, self.y)

    def __add__(self, other):
        return Point(self.parent, self.x + other.x, self.y + other.y)

# Create meta-model from the grammar. Provide `Point` class to be used for
# the rule `Point` from the grammar.
mm = metamodel_from_str(grammar, classes=[Point])

model_str = """
    move to 5, 10
    line to 10, 10
    line to 20, 20
    move by 5, -7
    circle 10
    line to 10, 10
"""

# Meta-model knows how to parse and instantiate models.
model = mm.model_from_str(model_str)

# At this point model is a plain Python object graph with instances of
# dynamically created classes and attributes following the grammar.

def cname(o):
    return o.__class__.__name__

# Let's interpret the model
position = Point(None, 0, 0)
for command in model.commands:
    if cname(command) == 'MoveTo':
        print('Moving to position', command.position)
        position = command.position
    elif cname(command) == 'MoveBy':
        position = position + command.vector
        print('Moving by', command.vector, 'to a new position', position)
    elif cname(command) == 'Circle':
        print('Drawing circle at', position, 'with radius', command.radius)
    else:
        print('Drawing line from', position, 'to', command.point)
        position = command.point
print('End position is', position)

# Output:
# Moving to position 5,10
# Drawing line from 5,10 to 10,10
# Drawing line from 10,10 to 20,20
# Moving by 5,-7 to a new position 25,13
# Drawing circle at 25,13 with radius 10
# Drawing line from 25,13 to 10,10

# Collect all points starting from the root of the model
points = get_children_of_type("Point", model)
for point in points:
    print('Point: {}'.format(point))

# Output:
# Point: 5,10
# Point: 10,10
# Point: 20,20
# Point: 5,-7
# Point: 10,10
四、定义一个可执行字符串表达式的模型

过程分两步进行:

  1. 定义元模型
  2. 构建解析器
1. 定义元模型

新建一个 .tx格式的文件,文件内容如下:

Model:
         assignments*=Assignment expression=Expression
         ;
Assignment:
         variable=ID '=' expression=Expression ';'
         ;
Expression:
          op=Not (op=Logic op=Not)*
           ;
Logic:
        "and" | "or" | "in"
           ;
Not:
    _not?='not' op=Compare
        ;
Compare:
          op=AddSub (op=CompareSymbol op=AddSub)*
           ;
CompareSymbol:
        "<=" | ">=" | ">" | "<" | "=" | "!="
       ;
AddSub:
         op=Term (op=PlusOrMinus op=Term)*
           ;
PlusOrMinus:
           '+' | '-'
           ;
Term:
     op=Factor (op=MulOrDiv op=Factor)*
     ;
MulOrDiv:
       '*' | '/'
       ;
Factor:
      (sign=PlusOrMinus)?  op=Operand
      ;
Operand:
        op=NUMBER | op=BOOL | op=ID | op=STRING | ('(' op=Expression ')')
      ;

2. 构建解析器

新建一个py文件,文件内容如下:

from __future__ import unicode_literals
from textx import metamodel_from_file


namespace = {}


def str_to_list(str_data: str):
    str_data = str_data
    return str_data


class Model(object):
    def __init__(self, **kwargs):
        self.assignments = kwargs.pop('assignments')
        self.expression = kwargs.pop('expression')

    @property
    def value(self):
        # Evaluate variables in the order of definition
        for a in self.assignments:
            namespace[a.variable] = a.expression.value
        return self.expression.value


class ExpressionElement(object):
    def __init__(self, **kwargs):
        # textX will pass in parent attribute used for parent-child
        # relationships. We can use it if we want to.
        self.parent = kwargs.get('parent', None)
        # We have 'op' attribute in all grammar rules
        self.op = kwargs['op']

        super(ExpressionElement, self).__init__()


class Expression(ExpressionElement):
    @property
    def value(self):
        ret = self.op[0].value
        for operation, operand in zip(self.op[1::2], self.op[2::2]):
            if operation == 'in':
                tag = True
                if ret[0] == '[':
                    ret = ret.lstrip('[')
                    if ret[-1] == ']':
                        ret = ret.rstrip(']').split(',')
                        for r in ret:
                            if r not in operand.value:
                                tag = False
                                break
                        ret = tag
                    else:
                        ret = ret in operand.value
                else:
                    ret = ret in operand.value
            elif operation == 'and':
                ret = ret and operand.value
            elif operation == 'or':
                ret = ret or operand.value
            elif operation == 'not':
                ret = not operand.value
        return ret


class Compare(ExpressionElement):
    @property
    def value(self):
        ret = self.op[0].value
        for operation, operand in zip(self.op[1::2], self.op[2::2]):
            if operation == '<':
                ret = ret < operand.value
            elif operation == '>':
                ret = ret > operand.value
            elif operation == '=':
                ret = ret == operand.value
            elif operation == '>=':
                ret = ret >= operand.value
            elif operation == '<=':
                ret = ret <= operand.value
            elif operation == '!=':
                ret = ret != operand.value
        return ret


class Not(ExpressionElement):
    def __init__(self, **kwargs):
        self._not = kwargs.pop('_not')
        super(Not, self).__init__(**kwargs)

    @property
    def value(self):
        ret = self.op.value
        return not ret if self._not else ret


class AddSub(ExpressionElement):
    @property
    def value(self):
        ret = self.op[0].value
        for operation, operand in zip(self.op[1::2], self.op[2::2]):
            if operation == '+':
                ret += operand.value
            else:
                ret -= operand.value
        return ret


class Term(ExpressionElement):
    @property
    def value(self):
        ret = self.op[0].value
        for operation, operand in zip(self.op[1::2], self.op[2::2]):
            if operation == '*':
                ret *= operand.value
            else:
                ret /= operand.value
        return ret


class Factor(ExpressionElement):
    def __init__(self, **kwargs):
        self.sign = kwargs.pop('sign', '+')
        super(Factor, self).__init__(**kwargs)

    @property
    def value(self):
        value = self.op.value
        return -value if self.sign == '-' else value


class Operand(ExpressionElement):
    @property
    def value(self):
        op = self.op
        if op in namespace:
            return namespace[op]
        elif type(op) in {int, float, bool, str}:
            return op
        elif isinstance(op, ExpressionElement):
            return op.value
        else:
            raise Exception('Unknown variable "{}" at position {}'
                            .format(op, self._tx_position))


# Meta.tx 为上面定义的元模型
meta = metamodel_from_file('Meta.tx',
                           classes=[Model, Expression, Not, Compare, AddSub, Term, Factor, Operand])

3. 构建完成

经过上面两个步骤,生成两个文件就代表模型已构建完成

4. 使用构建的模型


文件结构如上图: Meta.tx 是元模型, Model.py 是构建的解析器。
代码如下(示例)

from example.Model import meta
# 该模型用于判断字符串表达式

# 字符串表达式
rule = "(current_medical_program = '白细胞计数') and (specimen_type = '全血') and " 
       "(medicine_projects in '[1,2,3]') and (time < 6)"

# 正例数据
true_example = "current_medical_program = '白细胞计数';specimen_type = '全血';medicine_projects = '2';time = 5;"

# 反例数据
false_example = "current_medical_program = '白细胞计数';specimen_type = '全血';medicine_projects = '2';time = 8;"

print(meta.model_from_str(true_example + rule).value) # 结果:True


print(meta.model_from_str(false_example + rule).value) # 结果:False
           

textx-model介绍

textx-model是以textX为基础构建出可运行条件规则语句然后输出结果的模型,文章链接:https://blog.csdn.net/weixin_44836662/article/details/124812067

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/916163.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号