将Vimscript字典导出为JSON

时间:2014-04-26 20:17:38

标签: json vim

我找到了一个插件,可以让Vim解析JSON。我需要将VimScript字典导出为JSON。目前我只是在使用:

let str = string(dict)
substitute(str, "'", '"', 'g')

这是有效的,但是当我遇到带嵌入式引号的字典时,它肯定会中断。什么是更好的方式?

5 个答案:

答案 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以检查复杂变量