我找到了一个插件,可以让Vim解析JSON。我需要将VimScript字典导出为JSON。目前我只是在使用:
let str = string(dict)
substitute(str, "'", '"', 'g')
这是有效的,但是当我遇到带嵌入式引号的字典时,它肯定会中断。什么是更好的方式?
答案 0 :(得分:3)
我不确定这是否应该是一个单独的答案,编辑@ Kent的答案,或评论@ Kent的答案。这是@ Kent函数的一个版本,只有一些简化:
function! ToJson(input)
let json = ''
if type(a:input) == type({})
let json .= "{"
let di = 0
for key in keys(a:input)
let di += 1
let json .= '"'.escape(key, '"').'":'
let json .= ToJson(a:input[key])
let json .= di<len(a:input)? "," : ""
endfor
let json .= "}"
elseif type(a:input) == type([])
let json .= "["
let li = 0
for e in a:input
let li += 1
let json .= ToJson(e)
if li<len(a:input)
let json .= ","
endif
endfor
let json .= "]"
else
let json .= '"'.escape(a:input, '"').'"'
endif
return json
endfunction
不是回显结果,而是将其作为String返回。另外,我使用escape()
代替substitute()
。最后,我认为(检查这个!)使用escape()
是安全的,因为我没有先检查参数是否为String。
这是一个较短的版本,使用map()
。我不知道这个版本或其他版本的递归深度是否更重要,但如果你的输入足够重要,那么如果让map()
处理递归,它可能会更快。
function! ToJson(input)
let json = ''
if type(a:input) == type({})
let parts = copy(a:input)
call map(parts, '"\"" . escape(v:key, "\"") . "\":" . ToJson(v:val)')
let json .= "{" . join(values(parts), ",") . "}"
elseif type(a:input) == type([])
let parts = map(copy(a:input), 'ToJson(v:val)')
let json .= "[" . join(parts, ",") . "]"
else
let json .= '"'.escape(a:input, '"').'"'
endif
return json
endfunction
使用任一版本,我获得与@ Kent的函数相同的结果,除了空格。我没有用比@ Kent d1
更复杂的东西来测试它。使用deepcopy()
而不是copy()
可能更安全。
答案 1 :(得分:2)
我向echo
json字符串写了一个小函数,其中"
双引号被转义。不确定它是否适合您的需求:
function! ToJson(input)
if type(a:input) == type({})
echo "{"
let di = 0
for key in keys(a:input)
let di += 1
if type(key) == type('')
echo '"'.substitute(key, '"', '\\"','g').'":'
else
echo '"'.key.'":'
endif
call ToJson(a:input[key])
echo di<len(a:input)? "," : ""
endfor
echo "}"
elseif type(a:input) == type([])
echo "["
let li = 0
for e in a:input
let li += 1
call ToJson(e)
if li<len(a:input)
echo ","
endif
endfor
echo "]"
elseif type(a:input) == type('')
echo '"'.substitute(a:input, '"', '\\"','g').'"'
else
echo '"'.a:input.'"'
endif
endfunction
像这样的词典:
let d1={'one':'"""', 'two':123, 333:['11',22,'"_"_"'], 'four':"''"}
将输出为:
{
"four":
"''"
,
"one":
"\"\"\""
,
"two":
"123"
,
"333":
[
"11"
,
"22"
,
"\"_\"_\""
]
}
我没有做太多的调试/测试。格式看起来不太好,但我猜你不关心格式,因为你使用了string()
......
上述输出可以格式化为(通过在线json格式化程序):
{
"four":"''",
"one":"\"\"\"",
"two":"123",
"333":[
"11",
"22",
"\"_\"_\""
]
}
希望它有所帮助。
答案 2 :(得分:2)
WebAPI.vim插件有一个JSON解析器和编码器:
:let jsonString = webapi#json#encode({...})
答案 3 :(得分:2)
在我的原始答案之后两年半,有一个更简单的选择:升级到Vim 8并使用json_encode()
或(如果您不需要严格的JSON)js_encode()
。
答案 4 :(得分:0)
根据@benjifisher的回答,我进化了ToJson
。
缩进很麻烦,但大部分都有效。
" Inspect variables
"
" input: variable
" level: actual level of nest
" max: maximum level of nest let json = ''
function! ToJson(input, level, max)
if a:level < a:max
if type(a:input) == type({})
let parts = copy(a:input)
call map(parts, '"\"" . escape(v:key, "\"") . "\":" . ToJson(v:val, ' . (a:level+1) . ',' . a:max . ")")
let space = repeat(" ", a:level)
let json .= space . " {\r\n " . space . join(values(parts), ",\r\n " . space) . "\r\n" . space ." }"
elseif type(a:input) == type([])
let parts = map(copy(a:input), 'ToJson(v:val,' . (a:level+1) . ',' . a:max . ')')
let json .= "[" . join(parts, ",\r\n") . "]\r\n"
elseif type(a:input) == type(function("tr"))
let dictFunc = substitute(string(a:input), "function('\\(.\\+\\)')", "\\1", "")
if dictFunc+0 > 0
let funcName = '{' . dictFunc . '}'
else
let funcName = a:input
endif
let json .= '"'.escape(genutils#ExtractFuncListing(funcName, 0, 0), '"') . "\""
else
let json .= '"'.escape(a:input, '"') . "\""
endif
else
try
let json .= '"' . escape(string(a:input), '"') . "\""
catch
"string() can throw an E724 (too much nest)
let json .= '"' . escape(keys(a:input), '"') . "\""
endtry
endif
return json
endfunction
要显示函数定义,您需要https://github.com/vim-scripts/genutils的依赖关系:
https://github.com/vim-scripts/genutils/blob/master/autoload/genutils.vim#L57
如果该部分不适用于您,则省略该部分应该用于可视vim调试器vim-breakpts以检查复杂变量