0

我正在使用 Ruamel Python 库以编程方式更新人工编辑的 YAML 文件。

我有这样的数据:

---
a:
  b: '1'
  c: "2"

  d: 3
  # Comment.
  e: 4

我事先不知道评论会在哪里,空行会在哪里。

我需要将其重置为:

---
a:
  b: '1'   
  c: "2"
  d: 3
  # Comment.
  e: 4

我可以从以前的 答案中看到如何简单地删除所有评论,但我不知道如何查看 CommentToken 以查看它是否包含我需要保留的评论。

4

3 回答 3

0

它并没有像我问的那样专门解决问题,但是对于它的价值,我最终得到了这个:

data = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)

space, no_space = map(lambda x:
    [None, None, ruamel.yaml.tokens.CommentToken(x, \
        ruamel.yaml.error.CommentMark(0), None), None], ['\n\n', '\n'])

for key in data['a'].ca.items:
    data['a'].ca.items[key] = no_space

last = data['a'].keys()[-1]
data['a'].ca.items[last] = space

即我现在只是放弃保留任何非空间评论。

于 2017-03-12T23:09:19.890 回答
0

FWIW,我最终得到了以下内容。这将删除任何在剥离时为空的注释,即只有空格。包含任何实际内容的评论将被保留。

import ruamel.yaml

def monkeypatch_emitter():
    ruamel.yaml.emitter.Emitter.old_write_comment = ruamel.yaml.emitter.Emitter.write_comment

    def write_comment(self, comment, *args, **kwargs):
        if comment.value.strip():
            self.old_write_comment(comment, *args, **kwargs)

    ruamel.yaml.emitter.Emitter.write_comment = write_comment

def main():
    yaml = ruamel.yaml.YAML()
    # do yaml stuff here

if __name__ == '__main__:
    monkeypatch_emitter()
    main()

自从添加了上面的答案以来,签名可能已经发生了一些变化write_comment,因为它由于偶尔存在“pre”关键字参数而失败。如果将来再次更改,上面的代码应该传递任何额外的参数。

于 2018-12-21T20:58:52.330 回答
0

ruamel.yaml 的早期版本不会保留空行,但是通过在所有注释发出时通过的位置剥离换行符来恢复这种行为相对容易:Emitter.write_comment()in ruamel/yaml/emitter.py。幸运的是,由空格后跟换行符组成的行已经简化为换行符。本质上,不是在您的数据中搜索附加的评论并弄清楚如何重写它们,而是让评论来找您。

我包含了一些更多的空注释行案例来测试功能:

import sys
import ruamel.yaml

yaml_str = """\
---
a:
  b: '1'
  # comment followed by empty lines


  c: "2"

  d: 3
  # Comment.
  e: 4


  # empty lines followed by comment
  f: 5

  # comment between empty lines

  g: |+
    an empty line within a multi-line literal

    with a trailing empty line that is not stripped

  h: 6

# final top level comment
"""

# rename the comment writer
ruamel.yaml.emitter.Emitter.write_comment_org = ruamel.yaml.emitter.Emitter.write_comment


# define your own comment writer that calls the orginal if the comment is not empty
def strip_empty_lines_write_comment(self, comment):
    # print('{:02d} {:02d} {!r}'.format(self.column, comment.start_mark.column, comment.value))
    comment.value = comment.value.replace('\n', '')
    if comment.value:
        self.write_comment_org(comment)

# install
ruamel.yaml.emitter.Emitter.write_comment = strip_empty_lines_write_comment

data = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)
ruamel.yaml.round_trip_dump(data, sys.stdout)

给出:

a:
  b: '1'
  # comment followed by empty lines
  c: "2"
  d: 3
  # Comment.
  e: 4
  # empty lines followed by comment
  f: 5
  # comment between empty lines
  g: |+
    an empty line within a multi-line literal

    with a trailing empty line that is not stripped

  h: 6
# final top level comment

这当然会影响“安装”后的所有转储数据strip_empty_lines_write_comment。如果您的程序还需要使用空行转储数据,那么您需要基于子类StrippingEmitterEmitter使用该子类创建StrippingRoundTripDumper(如RoundTripDumperin ruamel/yaml/dumper.py)。

(您当然可以从代码中删除注释掉的调试打印语句)

于 2017-03-10T07:33:32.103 回答