我正在尝试实现将原始文本数据转换为JSON格式的解析器。文本如下。
(一个例子)
>图片网址(可选)
###物品名称2
元素的顺序将按照给定的顺序。
我想要的期望输出如下:
{
name: "menu name",
sections: [
{
name: "Section name",
items: [{
name: "item name",
description: "description",
price: 23.00
},
{
name: "item name",
description: "description",
price: 43.00
},
]
}
]
}
注意:每个部分可以有多个项目,每个菜单可以有多个部分。因此应保持顺序,即,如果出现新的部分,则下面的项目现在应成为该部分的一部分。
我尝试了使用String解析的解决方案,并且工作正常,但是我想知道执行此任务的标准方法。
答案 0 :(得分:1)
由于预期的输出是JSON,因此使用诸如jq之类的面向JSON的工具可能有意义。当然,有许多不同的可能方法,但是至少对于那些熟悉JSON查询语言的人来说,这是一种简单,直接,易于扩展并且在某些方面易于理解的方法。
下面的程序将为每个“菜单”(即每次出现“#菜单名称”行)产生一个JSON对象。
# The next key name in an item
def keyname:
if (.description | not) then "description"
elif (.price | not) then "price"
elif (.url | not) then "url"
else length|tostring
end;
def menu_name($s):
. += [{name: $s}];
def section_name($s):
.[-1].sections += [{name: $s}];
def item_name($s):
.[-1].sections[-1].items += [{name: $s}];
def item_description($s):
(.[-1].sections[-1].items[-1]|keyname) as $key
| .[-1].sections[-1].items[-1][$key] = $s;
reduce inputs as $in ([];
if $in|test("^ *$") then . # ignore blank lines
else ($in|split(" ")) as $tokens
| ($in|sub("[^ ]* *";"")) as $phrase
| if $tokens[0] == "#" then menu_name( $phrase )
elif $tokens[0] == "##" then section_name( $phrase )
elif $tokens[0] == "###" then item_name( $phrase )
elif $tokens[0] == ">" then item_description( $phrase )
else .
end
end )
| .[] # stream the menus
以上使用inputs
,因此-n
命令行选项很重要:
jq -n -f menus.jq input.txt
使用示例输入:
{
"name": "Menu Name",
"sections": [
{
"name": "Section Name",
"items": [
{
"name": "Item Name",
"description": "Description",
"price": "Price",
"url": "Image URL (optional)"
},
{
"name": "Item Name 2",
"description": "Description",
"price": "Price",
"url": "Image URL (optional)"
}
]
}
]
}