【问题标题】:Iterating over a string in Vimscript or Parse a JSON file遍历 Vimscript 中的字符串或解析 JSON 文件
【发布时间】:2013-07-19 16:34:55
【问题描述】:

所以我正在创建一个 vim 脚本,该脚本需要将 JSON 文件加载并解析到本地对象图中。我进行了搜索,但找不到任何处理 JSON 文件的本机方式,并且我不想向脚本添加任何依赖项。所以我编写了自己的函数来解析 JSON 字符串(从文件中获取),但它真的很慢。目前,我像这样遍历文件中的每个字符:

let len = strlen(jsonString) - 1
let i = 0
while i < len
    let c = strpart(jsonString, i, 1)
    let i += 1
    " A lot of code to process file....
    " Note: I've tried short cutting the process by searching for enclosing double-quotes when I come across the initial double quotes (also taking into account escaping '\' character.  It doesn't help
endwhile

这个方法我也试过了:

for c in split(jsonString, '\zs')
    " Do a lot of parsing ....
endfor

作为参考,处理约 29,000 个字符的文件大约需要 4 秒,这是不可接受的。

有没有更好的方法来遍历 vim 脚本中的字符串?

或者更好的是,我是否错过了解析 JSON 的本机函数?

更新:

我要求不依赖,因为我:

  1. 不想和他们打交道
  2. 真心想要一些想法,以找到无需他人工作的最佳方式。
  3. 有时我只是喜欢手动操作,即使问题已经解决了。

我根本不反对插件或依赖项,只是我很好奇。因此问题。

我最终创建了自己的函数来解析 JSON 文件。我正在创建一个可以解析与 node.js 模块关联的 package.json 文件的脚本。因此,只要我检索到所需的信息,我就可以依靠相当一致的格式并退出处理。这通常会删除文件的大块,因为大多数开发人员将文件的最大块,即他们的“自述文件”部分放在最后。因为package.json 文件是严格定义的,所以我让这个过程有些脆弱。它假定一个根字典{ } 并积极寻找某些条目。你可以在这里找到脚本:https://github.com/ahayman/vim-nodejs-complete/blob/master/after/ftplugin/javascript.vim#L33。

当然,这并不能回答我自己的问题。这只是我独特问题的解决方案。我会等几天等待新的答案,并在赏金结束前挑选出最好的答案(我已经在手机上设置了闹钟)。

【问题讨论】:

标签: json string parsing vim


【解决方案1】:

依赖最少的最简单解决方案就是使用json_decode vim 函数。

let dict = json_decode(jsonString)

【讨论】:

  • 需要注意的是,该支持是在 vim8 中添加的(在此之前它也存在于 Neovim 中)。
【解决方案2】:

尽管 Vim 的起源可以追溯到很久以前,但它的内部 string() eval() 表示非常接近 JSON,除非你需要特殊字符,否则它可能会工作。

如果需要,您可以在此处查找甚至支持 true/false/null 的实现: https://github.com/MarcWeber/vim-addon-json-encoding

更好地使用该库(vim-addon-manager 允许轻松安装依赖项)。 现在这是否足够好取决于您的数据。

现在 Benjamin Klein 将您的问题发布到 vim_use 这就是我回复的原因。 如果你订阅了 Vim 邮件列表,就会得到最好和最快速的回复。 转到 vim.sf.net 并点击社区链接。 你不能指望 Vim 社区会刮掉 stackoverflow。

我已将关键字“json”和“解析”添加到可以更容易找到的小代码中。

如果这个解决方案对你不起作用,你可以尝试许多 :h if_* 绑定或编写一个外部脚本来提取你正在寻找的信息,或者将 JSON 转换为 Vim 的字典表示形式,可以通过 eval( ) 正确转义您关心的特殊字符。

【讨论】:

  • 在 VAM-kr 我们使用这个代码:eval(join(readfile(file, 'b'), ''))。在较旧的 Vim 版本中,加入速度很慢,因此如果您在类似 unix 的环境中,请考虑使用 system('cat file') 代替。 webapi支持解析xml; github.com/mattn/webapi-vim.git
  • [webapi](github.com/mattn/webapi-vim.git) 正在使用 matchlist() 和正则表达式。在 vim.sf.net 上某处有一个 java 词法分析器。但最终 VimL 是众所周知的,如果你有很多数据,它是错误的工具。我已经痛苦地学到了很多次。
  • 令我惊讶的是,在您的插件中,您没有使用现有解决方案来保护 VAM 中使用的 eval。另外切勿使用== 进行字符串比较。有==# 和is#。 Funcrefs 对于特殊值看起来更好(因为它们不可能以任何其他方式在 JSON 中编码),你为什么要评论它们?
  • string(json_encoding#*()) 在line 47 及以下调用也是很好的缓存候选对象。
  • 放置此类“变更请求”和“提示”的正确位置是 github,而不是堆栈溢出注释
【解决方案3】:

如果您寻求完全正确的解决方案,忽略依赖项是您能做的最糟糕的事情之一。 @MarcWeber 提到的 eval() 变体是最快的变体之一,但它也有其缺点:

  1. 使用我在评论中提到的solution for securing eval 使其不再是最快的。事实上,在你使用它之后,它会使eval() 变慢一个数量级以上(在我的测试中为 0.02 秒对 0.53 秒)。
  2. 它不尊重代理对。
  3. 它不能用于验证您是否拥有正确的 JSON:它接受一些不是 JSON 字符串的字符串(例如 "\&lt;C-o&gt;"),并且它允许尾随逗号。
  4. 它无法给出正常的错误消息。如果您使用我在第 1 页中提到的vam#VerifyIsJSON,它会严重失败。
  5. 它无法加载像 1e10 这样的浮点值(vim 要求数字看起来像 1.0e10,但像 1e10 are allowed 这样的数字:请注意第一段中的“和/或”)。

。以上所有(除了第一个)语句也适用于@MarcWeber 提到的vim-addon-json-encoding,因为它使用了eval。还有一些其他的可能性:

  1. 最快最正确的是使用python:pyeval('json.loads(vim.eval("varname"))')。不比 eval 快,但在其他可能性中最快。 (在我的测试中为 0.04:大约比 eval() 慢两倍)

    请注意,我在这里使用pyeval()。如果您想要缺少此功能的 vim 版本的解决方案,它将不再是最快的解决方案之一。

  2. 使用我的json.vim 插件。与失败的vam#VerifyIsJSON 相比,它的错误报告稍好一些,与eval() 相比稍差一些,并且它可以正确加载浮点数。它可用于验证字符串(它不接受"\&lt;C-a&gt;"),但它可以很好地加载带有逗号结尾的列表。它不支持代理对。它也很慢:在我使用的测试中(它使用 279702 个字符的长字符串)加载需要 11.59 秒。如果可能,Json.vim 会尝试使用 python。

  3. 为了获得最佳错误报告,您可以使用 yaml.vim 并从中清除 YAML 支持,只留下 JSON(我曾经为 pyyaml 做过同样的事情,但在 python 中:参见 markedjson library used in powerline:它是 pyyaml 减去 YAML 的东西加上带分数的课程)。但是这个变种甚至比 json.vim 还要慢,并且只应该在您需要的主要内容是错误报告时使用:加载相同的 279702 字符长字符串需要 207 秒。

请注意,唯一提到的同时满足“无依赖关系”和“无 python”要求的变体是eval()。如果您对它的缺点不满意,则必须放弃其中一项或两项要求。或者复制粘贴代码。虽然如果考虑到速度,只剩下两个候选者:eval() 和 python:如果你想快速解析 json,你真的必须使用 C,而且只有这些解决方案将大部分时间花在用 C 编写的函数上。

大多数其他解释器 (ruby/perl/TCL) 没有 pyeval() 等效项,因此即使它们的 JSON 实现是用 C 编写的,它们也会变慢。其他一些 (lua/racket (mzscheme)) 具有 pyeval() 等效项,但例如luaeval('{}') 为零,这意味着您必须显式添加额外的步骤并递归地将对象转换为 vim 字典和列表(例如 luaeval('vim.dict({})')),这将影响性能。不能说任何关于mzeval() 的事情,但我从来没有听说过有人在 vim 中实际使用球拍(mzscheme)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 2019-08-16
    • 2021-12-18
    相关资源
    最近更新 更多