2014-04-26 77 views
3

我找到了一個使Vim能夠解析JSON的插件。我需要將VimScript字典導出爲JSON。目前,我只是用:將Vimscript Dictionary導出爲JSON

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

這是工作,但勢必打破,當我運行與嵌入式引號字典。什麼是更好的方法?

+0

什麼插件? JSON-to-Vim插件的意義何在? – romainl

回答

2

WebAPI.vim插件有一個JSON解析器和編碼器:

:let jsonString = webapi#json#encode({...}) 
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", 
     "\"_\"_\"" 
    ] 
} 

希望它有幫助。

3

我不確定這應該是一個單獨的答案,編輯@肯特的答案,或評論@肯特的答案。這裏是一個版本@肯特與一些簡化功能:

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 

相反呼應的結果,它返回它作爲一個字符串。此外,我使用escape()而不是substitute()。最後,我認爲(檢查這個!)可以安全地使用escape(),因爲我沒有首先檢查參數是否是字符串。

這是一個較短的版本,使用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()更安全。

+0

+1你的答案。我也嘗試使用'escape()',但是我可能會犯一些愚蠢的錯誤,在輸出中沒有'slash'。我沒有進一步測試並使用'sub ..()'。同樣對於地圖,我也想到了它,但是我需要在每個遞歸步驟中使用'deepcopy'這個對象,並且我認爲如果字典具有相對更多的嵌套層次,它可能會成爲一些問題。但我沒有深思。 – Kent

0

基於@benjifisher答案,我發展ToJson

縮進是hacky,但主要是工作。

" 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用於檢查複雜的變量

2

兩年半後,我的原始答案,有一個更簡單的替代:升級到Vim 8和使用json_encode()或(如果你不需要嚴格t JSON)js_encode()