对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'
更新信息:
我认为我在没有更多上下文的情况下,把这些例子放在自己的台词上是误导人的。下面是一个真实的例子:
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对),其他任何东西都会引发解析错误,因为后面可能会有更多的标记(同一行),但是数字本身是无效的。
希望这能让事情变得更清楚。
发布于 2012-03-28 10:38:41
好吧,这就是我最后想出来的,使用scanString。
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发布于 2012-03-28 14:14:47
作为对OP编辑的响应,下面的答案已经不完整了.
我将试着在这里讨论你问题的核心,忽略更详细的细节。希望它能让你走上正确的轨道,掌握你的其他语法。从本质上讲,考虑到这两句话,你是在问:
P 3 811 190 815 180 806 185
P 2 811 190 815 180 806 185如何解析数据,以便在第二行中只读取两个点?就我个人而言,我会阅读所有的数据和分析后。如果您将结果命名为,那么您可以极大地简化您自己的工作。例如:
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, flag和length名称,这将在以后派上用场。让我们解析和处理字符串:
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()给出有用和有条理的结果:
[['P', 3], [[811, 190], [815, 180], [806, 185]]]
[['P', 2], [[811, 190], [815, 180]]]扩展语法
从这里开始,你可以一个一个地独立地构建语法片段。每次添加新类型时,都将其添加到xdot_line中,即
xdot_line = Group(poly_type | pen_fill_type) + EOLhttps://stackoverflow.com/questions/9898984
复制相似问题