【问题标题】:Stop PyYaml from converting a yaml item to list阻止 PyYaml 将 yaml 项目转换为列表
【发布时间】:2020-02-17 15:12:36
【问题描述】:

我正在尝试加载以下 yaml:

yaml_string = """
key:
- [HELLO]
- another string
- another
"""
yaml.safe_load(yaml_string) # returns {"key": [["HELLLO"], "another_string", "another"}

结果是一个包含 HELLO 字符串的列表。我想加载一个字符串值,即

type(yaml.save_load(yaml_string).get("key")[0])
<class 'str'>

由于 yaml 描述了某种以这种方式格式化的命令,因此有必要将其作为字符串而不是序列来读取。基本上我希望能够读取以括号开头和结尾的字符串。正如下面的评论所解释的,不幸的是,无法添加",因为 yaml 文件是由使用 Jackson 的 Java 应用程序创建的,将 yaml 转换为对象并处理以括号开头和结尾的条目没有问题作为字符串。这些文件很多,用户可以开始添加引号。

这可能吗?

编辑:添加了更完整的示例

【问题讨论】:

  • 如果你想要一个字符串,那么你为什么要使用-[ .. ]?这些使值成为列表列表
  • 我编辑了我的问题。在 yaml 中,它是项目列表的键。我想要他们所有的字符串
  • 您仍然没有解释为什么在HELLO 周围添加[...]
  • 所以,要明确一点,你想要{"key": [["HELLLO"], "another_string", "another"}而不是{"key": ["[HELLLO]", "another_string", "another"}
  • 不可能像字符串一样读取这些项目(以一般方式)。 [...] 是官方 YAML 语法的一部分(就像在 JSON 中一样)。它被称为流样式(与默认的块样式相反)。您必须实现一个忽略流式语法的解析器。基本上,如果您希望 [foo] 是一个字符串 "[foo]",那么您所拥有的不是 YAML。

标签: python yaml pyyaml


【解决方案1】:

用引号包围[HELLO]

import yaml

yaml_string = """
key:
- "[HELLO]"
- another string
- another
"""

print(yaml.safe_load(yaml_string))

输出

{'key': ['[HELLO]', 'another string', 'another']}

【讨论】:

  • 是的,这是不可能的,因为我的大部分 yaml 文件都是自动创建的,不包含引号,而且太多了。 pyyaml 默认情况下有没有办法做到这一点。一般来说,我希望 pyyaml 跳过转换为布尔值列表等。我希望它们是纯字符串。我想在不同的步骤中处理投射
  • @Apo 你可以使用正则表达式替换,不是吗?
  • @cricket_007 可能非常脆弱,因为可能有其他位置带有 [ 字符
  • @tinita 所以?你可以匹配-\s+\[[^]+\]
  • @cricket_007 当然,如果有问题的“字符串”总是一个序列项并且- [...] 没有出现在其他任何地方,它可能会起作用。我不知道完整的 YAML 文件是什么样子的。正则表达式替换和我的解决方案都有优点和缺点
【解决方案2】:

如果您想要字符串 "HELLO" 作为结果,请在 YAML 中删除它周围的 [...]

yaml_string = """
key:
- HELLO
"""
print(yaml.safe_load(yaml_string))
# {'key': ['HELLO']}

如果您想要字符串 "[HELLO]"(而不是包含字符串 "HELLO" 的列表),请在 YAML 中添加引号:

yaml_string = """
key:
- "[HELLO]"
"""
print(yaml.safe_load(yaml_string))
# {'key': ['[HELLO]']}

【讨论】:

    【解决方案3】:

    [] 语法是 YAML 语法的一部分。如果您使用程序创建它并且这些应该是字符串,那么您使用的程序没有正确实现 YAML,因为字符串必须被引用。

    您可以尝试以下实验性 perl 脚本来在 [...] 周围添加引号。这依赖于您的文档不使用应该是真实序列的流式序列的假设。此外,它可能不适用于所有情况。

    如果字符串只有一个开头 [ 而没有结尾,那肯定不行。

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use 5.010;
    
    use YAML::LibYAML::API::XS;
    
    my $yaml = <<'EOM';
    key:
    - [HELLO]
    - another string
    - another
    - [HELLO2]
    EOM
    
    my @lines = split /(?<=\n)/, $yaml;
    
    my @events;
    YAML::LibYAML::API::XS::parse_string_events($yaml, \@events);
    while (my $event = shift @events) {
        if ($event->{name} eq 'sequence_start_event' and $event->{style} == 2) {
            my $start = $event->{start};
            my $line = $start->{line};
            my $column = $start->{column};
            # Add single quote before [
            substr($lines[ $line ], $column, 0) = "'";
            # find the next matching `]`
            while (my $event = shift @events) {
                if ($event->{name} eq 'sequence_end_event') {
                    my $end = $event->{end};
                    my $line = $end->{line};
                    # Add single quote after ]
                    # add 1 because we modified the line already and added one char
                    my $column = $end->{column} + 1;
                    substr($lines[ $line ], $column, 0) = "'";
                    last;
                }
            }
        }
    }
    
    $yaml = join '', @lines;
    say $yaml;
    

    如果你有 libyaml API 的接口,你也许可以用 Python 做同样的事情。

    输出:

    key:
    - '[HELLO]'
    - another string
    - another
    - '[HELLO2]'
    

    【讨论】:

      猜你喜欢
      • 2012-12-16
      • 2015-12-31
      • 2021-07-17
      • 1970-01-01
      • 2021-04-18
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 2019-05-14
      相关资源
      最近更新 更多