首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Parsing解析xdot绘制属性

用Parsing解析xdot绘制属性
EN

Stack Overflow用户
提问于 2012-03-27 23:04:02
回答 2查看 203关注 0票数 2

对PyParsing来说是新手。我正在努力解决如何解析xdot文件中的绘图(和类似的)属性。有许多项在开始时将下列元素的数目作为整数给出--有点类似于NetStrings。我看过一些处理netstring (如构造)的示例代码,但它似乎不适合我。

以下是一些样本:

3点多边形(P后面的3表示以下点数):

P 3 811 190 815 180 806 185应该解析为'P', [[811, 190], [815, 180], [806, 185]]

多边形有2分:

P 2 811 190 815 180 806 185应该解析为'P', [[811, 190], [815, 180]] (末尾是未解析的文本)

钢笔填充颜色(C后面的4个表示消费“-”之后的字符数):

C 4 -blue应该解析为'C', 'blue'

更新信息:

我认为我在没有更多上下文的情况下,把这些例子放在自己的台词上是误导人的。下面是一个真实的例子:

代码语言:javascript
复制
S 5 -solid S 15 -setlinewidth(1) c 5 -black C 5 -black P 3 690 181 680 179 687 187

有关实际规范,请参见http://www.graphviz.org/doc/info/output.html#d:xdot

注意,文本字段中可能有重要的空格在'P‘标签后面应该正好有7个数字(初始计数器+3对),其他任何东西都会引发解析错误,因为后面可能会有更多的标记(同一行),但是数字本身是无效的。

希望这能让事情变得更清楚。

EN

回答 2

Stack Overflow用户

发布于 2012-03-28 10:38:41

好吧,这就是我最后想出来的,使用scanString。

代码语言:javascript
复制
int_ = Word(nums).setParseAction(lambda t: int(t[0]))
float_ = Combine(Word(nums) + Optional('.' + ZeroOrMore(Word(nums, exact=1)))).setParseAction(lambda t: float(t[0]))
point = Group(int_ * 2 ).setParseAction(lambda t: tuple(t[0]))
ellipse = ((Literal('E') ^ 'e') + point + int_ + int_).setResultsName('ellipse')
n_points_start =  (Word('PpLBb', exact=1) + int_).setResultsName('n_points')
text_start = ((('T' + point + int_*3 ) ^ ('F' + float_ + int_) ^ (Word('CcS') + int_) ) + '-').setResultsName('text')
xdot_attr_parser = ellipse ^ n_points_start ^ text_start

def parse_xdot_extended_attributes(data):
    results = []
    while True:
        try:
            tokens, start, end = xdot_attr_parser.scanString(data, maxMatches = 1).next()
            data = data[end:]
            name = tokens.getName()
            if name == 'n_points':
                number_to_get = int(tokens[-1])
                points, start, end = (point * number_to_get).scanString(data, maxMatches = 1).next()
                result = tokens[:1]
                result.append(points[:])
                results.append(result)
                data = data[end:]
            elif name == 'text':
                number_to_get = int(tokens[-2])
                text, data = data[:number_to_get], data[number_to_get:]
                result = tokens[:-2]
                result.append(text)
                results.append(result)
            else:
                results.append(tokens)
        except StopIteration:
            break
    return results
票数 1
EN

Stack Overflow用户

发布于 2012-03-28 14:14:47

作为对OP编辑的响应,下面的答案已经不完整了.

我将试着在这里讨论你问题的核心,忽略更详细的细节。希望它能让你走上正确的轨道,掌握你的其他语法。从本质上讲,考虑到这两句话,你是在问:

代码语言:javascript
复制
P 3 811 190 815 180 806 185
P 2 811 190 815 180 806 185

如何解析数据,以便在第二行中只读取两个点?就我个人而言,我会阅读所有的数据和分析后。如果您将结果命名为,那么您可以极大地简化您自己的工作。例如:

代码语言:javascript
复制
from pyparsing import *

EOL = LineEnd().suppress()

number = Word(nums).setParseAction(lambda x: int(x[0]))
point_pair = Group(number + number)

poly_flag  = Group(Literal("P") + number("length"))("flag")
poly_type  = poly_flag + Group(OneOrMore(point_pair))("data")

xdot_line = Group(poly_type) + EOL
grammar   = OneOrMore(xdot_line)

请注意,我们有一个data, flaglength名称,这将在以后派上用场。让我们解析和处理字符串:

代码语言:javascript
复制
S = "P 3 811 190 815 180 806 185\nP 2 811 190 815 180 806 185\n"
P = grammar.parseString(S)

for line in P:
    L = line["flag"]["length"]  
    while len(line["data"]) > L: 
        line["data"].pop()

给出有用和有条理的结果:

代码语言:javascript
复制
[['P', 3], [[811, 190], [815, 180], [806, 185]]]
[['P', 2], [[811, 190], [815, 180]]]

扩展语法

从这里开始,你可以一个一个地独立地构建语法片段。每次添加新类型时,都将其添加到xdot_line中,即

代码语言:javascript
复制
xdot_line = Group(poly_type | pen_fill_type) + EOL
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9898984

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档