Mit*_*ops 6 python parsec parser-combinators
我正在看这个图书馆,那里没有多少文档:https : //pythonhosted.org/parsec/#examples
我知道还有其他选择,但我想使用这个库。
我想解析以下字符串:
mystr = """
<kv>
key1: "string"
key2: 1.00005
key3: [1,2,3]
</kv>
<csv>
date,windspeed,direction
20190805,22,NNW
20190805,23,NW
20190805,20,NE
</csv>"""
Run Code Online (Sandbox Code Playgroud)
虽然我想解析整个事情,但我只想抓住<tags>。我有:
>>> import parsec
>>> tag_start = parsec.Parser(lambda x: x == "<")
>>> tag_end = parsec.Parser(lambda x: x == ">")
>>> tag_name = parsec.Parser(parsec.Parser.compose(parsec.many1, parsec.letter))
>>> tag_open = parsec.Parser(parsec.Parser.joint(tag_start, tag_name, tag_end))
Run Code Online (Sandbox Code Playgroud)
好,看起来不错 现在使用它:
>>> tag_open.parse(mystr)
Traceback (most recent call last):
...
TypeError: <lambda>() takes 1 positional argument but 2 were given
Run Code Online (Sandbox Code Playgroud)
这失败了。恐怕我什至不明白我的lambda表达式给出两个参数的含义,这很明显是1.如何进行?
对于所有奖励积分,我的最佳期望输出是:
[
{"type": "tag",
"name" : "kv",
"values" : [
{"key1" : "string"},
{"key2" : 1.00005},
{"key3" : [1,2,3]}
]
},
{"type" : "tag",
"name" : "csv",
"values" : [
{"date" : 20190805, "windspeed" : 22, "direction": "NNW"}
{"date" : 20190805, "windspeed" : 23, "direction": "NW"}
{"date" : 20190805, "windspeed" : 20, "direction": "NE"}
]
}
Run Code Online (Sandbox Code Playgroud)
在这个问题中,我准备理解的输出是使用上述函数来生成start和end标记:
[
{"tag": "kv"},
{"tag" : "csv"}
]
Run Code Online (Sandbox Code Playgroud)
并且只需能够从凌乱的混合文本条目中解析出任意类似xml的标签。
我鼓励您使用这些组合器定义自己的解析器,而不是Parser直接构造直接解析器。
如果要Parser通过包装函数来构造A ,如文档所述,fn则应接受两个参数,第一个是文本,第二个是当前位置。并且fn应返回Valueby Value.success或Value.failure,而不是布尔值。您可以在此软件包@Parser中的grep 中parsec/__init__.py找到有关其工作方式的更多示例。
对于描述中的情况,可以按如下方式定义解析器:
from parsec import *
spaces = regex(r'\s*', re.MULTILINE)
name = regex(r'[_a-zA-Z][_a-zA-Z0-9]*')
tag_start = spaces >> string('<') >> name << string('>') << spaces
tag_stop = spaces >> string('</') >> name << string('>') << spaces
@generate
def header_kv():
key = yield spaces >> name << spaces
yield string(':')
value = yield spaces >> regex('[^\n]+')
return {key: value}
@generate
def header():
tag_name = yield tag_start
values = yield sepBy(header_kv, string('\n'))
tag_name_end = yield tag_stop
assert tag_name == tag_name_end
return {
'type': 'tag',
'name': tag_name,
'values': values
}
@generate
def body():
tag_name = yield tag_start
values = yield sepBy(sepBy1(regex(r'[^\n<,]+'), string(',')), string('\n'))
tag_name_end = yield tag_stop
assert tag_name == tag_name_end
return {
'type': 'tag',
'name': tag_name,
'values': values
}
parser = header + body
Run Code Online (Sandbox Code Playgroud)
如果运行parser.parse(mystr),它会产生
({'type': 'tag',
'name': 'kv',
'values': [{'key1': '"string"'},
{'key2': '1.00005'},
{'key3': '[1,2,3]'}]},
{'type': 'tag',
'name': 'csv',
'values': [['date', 'windspeed', 'direction'],
['20190805', '22', 'NNW'],
['20190805', '23', 'NW'],
['20190805', '20', 'NE']]}
)
Run Code Online (Sandbox Code Playgroud)
您可以values在上面的代码中细化的定义,以获得所需形式的结果。
根据测试,解析字符串的正确方法如下:
from parsec import *
possible_chars = letter() | space() | one_of('/.,:"[]') | digit()
parser = many(many(possible_chars) + string("<") >> mark(many(possible_chars)) << string(">"))
parser.parse(mystr)
# [((1, 1), ['k', 'v'], (1, 3)), ((5, 1), ['/', 'k', 'v'], (5, 4)), ((6, 1), ['c', 's', 'v'], (6, 4)), ((11, 1), ['/', 'c', 's', 'v'], (11, 5))]
Run Code Online (Sandbox Code Playgroud)
的建设parser:
为了方便起见,我们首先定义我们希望匹配的字符。parsec提供多种类型:
letter(): 匹配任何字母字符,
string(str): 匹配任何指定的字符串str,
space(): 匹配任何空白字符,
spaces(): 匹配多个空白字符,
digit(): 匹配任何数字,
eof(): 匹配字符串的 EOF 标志,
regex(pattern): 匹配提供的正则表达式模式,
one_of(str): 匹配提供的字符串中的任何字符,
none_of(str): 匹配不在提供的字符串中的字符。
根据文档,我们可以用运算符将它们分开:
|:这个组合器实现选择。解析器 p | q 首先应用 p。如果成功,则返回 p 的值。如果 p 在不消耗任何输入的情况下失败,则尝试解析器 q。注意:没有回溯,
+: 将两个或多个解析器合二为一。返回来自这两个解析器的两个结果的聚合。
^: 选择回溯。每当需要任意前瞻时,就会使用此组合器。解析器 p || q首先应用p,如果成功,则返回p的值。如果 p 失败,它会假装它没有消耗任何输入,然后尝试解析器 q。
<<: 以指定的解析器结束,最后解析器消耗了结束标志,
<: 以指定的解析器结束,最后解析器没有消耗任何输入,
>>: 依次组合两个动作,丢弃第一个产生的任何值,
mark(p):标记解析器结果的行列信息p。
然后有多个“组合器”:
times(p, mint, maxt=None):重复解析器p从mint以maxt倍,
count(p,n): 重复解析器次p n。如果n小于或等于零,则解析器等于返回空列表,
(p, default_value=None):使解析器可选。如果成功,返回结果,否则default_value静默返回,不引发任何异常。如果default_value没有提供,None则返回,
many(p):p从从不到无限次重复解析器,
many1(p):重复解析器p至少一次,
separated(p, sep, mint, maxt=None, end=None): ,
sepBy(p, sep): 解析零次或多次出现的解析器p,由分隔符分隔sep,
sepBy1(p, sep): 解析至少出现一次解析器p,由分隔符分隔sep,
endBy(p, sep):解析零个或多个的p,分离和结束sep,
endBy1(p, sep):解析在至少一次出现的p,分离和结束sep,
sepEndBy(p, sep):解析零次或多次出现的p,分隔并可选地以sep,
sepEndBy1(p, sep): 解析至少一个出现的p,分隔并可选地以 结尾sep。
使用所有这些,我们有一个解析器,它匹配 many 的多次出现possible_chars,后跟 a <,然后我们标记possible_charsup的多次出现>。
| 归档时间: |
|
| 查看次数: |
286 次 |
| 最近记录: |