Поскольку ожидаемый результат - JSON, возможно, имеет смысл использовать JSON-ориентированный инструмент, такой как jq . Существует, конечно, много разных возможных подходов, но здесь есть простой, прямой, легко расширяемый и, в некотором смысле, простой для понимания, по крайней мере, для тех, кто знаком с языком запросов JSON.
Программа, представленная ниже, создаст один объект JSON для каждого «меню» (т. Е. Каждое вхождение строки «# Имя меню»).
menus.jq
# 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
1010 * Воззвание *
Выше используется 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)"
}
]
}
]
}