如何在Python中读取yaml文件时跳过行?

5

我熟悉类似的问题,但它们似乎没有解决应该是一个简单问题的内容。我正在使用Python 2.7x并尝试读取一个类似于这样的YAML文件:

%YAML:1.0
radarData: !!opencv-matrix
rows: 5
cols: 2
dt: u
data: [0, 0, 0, 0, 0, 10, 5, 3, 1, 22]

目前我只需要"data:"文档。我尝试了基本方法,然后试图强制跳过前4行(第二个被注释的代码片段)。这两种方法都导致错误。

import yaml
stream = file('test_0x.yml', 'r') 
yaml.load(stream)
# alternative code snippet
# with open('test_0x.yml') as f:
#  stream = f.readlines()[4:]
# yaml.load(stream)

有关如何跳过前几行的任何建议都将不胜感激。

3个回答

12

实际上,你只需要跳过前两行。

import yaml

skip_lines = 2
with open('test_0x.yml') as infile:
    for i in range(skip_lines):
        _ = infile.readline()
    data = yaml.load(infile)

>>> data
{'dt': 'u', 'rows': 5, 'data': [0, 0, 0, 0, 0, 10, 5, 3, 1, 22], 'cols': 2}
>>> data['data']
[0, 0, 0, 0, 0, 10, 5, 3, 1, 22]

跳过前5行也可以。


感谢两位抽出时间,但是@mhawke说的很对。顺便提一下,数据文件的一个版本有4行非YAML格式的代码。再次感谢! - Aengus
我内心挑剔的一面提醒你小心称呼这些行为“非YAML”。从长远来看,如果你遇到了很多我所谓的“不太严格”的YAML,最好构建预处理步骤,以使数据强健地符合规范,而不是依赖于数据中键的顺序。话虽如此,不要修复没有问题的东西。 - spirulence

3

我有一个由aruco_calibration_fromimages.exe生成的相机矩阵,这是yml文件:

%YAML:1.0
---
image_width: 4000
image_height: 3000
camera_matrix: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 3.1943912478853654e+03, 0., 1.9850941722590378e+03, 0.,
       3.2021356095317910e+03, 1.5509955246019449e+03, 0., 0., 1. ]
distortion_coefficients: !!opencv-matrix
   rows: 1
   cols: 5
   dt: d
   data: [ 1.3952810090687282e-01, -3.8313647492178071e-01,
       5.0555840762660396e-03, 2.3753464602670597e-03,
       3.3952514744179502e-01 ]

使用以下代码加载此 yml 文件:

import cv2
fs = cv2.FileStorage("./calib_asus_chess/cam_calib_asus.yml", cv2.FILE_STORAGE_READ)
fn = fs.getNode("camera_matrix")
print(fn.mat())

并获得以下结果:

[[  3.19439125e+03   0.00000000e+00   1.98509417e+03]
 [  0.00000000e+00   3.20213561e+03   1.55099552e+03]
 [  0.00000000e+00   0.00000000e+00   1.00000000e+00]]

1
我完全没理解这里的重点,但我将我的原始答案放在底部作为谦卑的提醒。
mhawke 的答案简短而精炼,可能更可取。更复杂的解决方案是:删除该格式错误的指令,纠正您的自定义标签,并为其添加构造函数。这样做的优点是可以在文件中的任何位置纠正该标记,而不仅仅是在前几行中。
我的实现确实有一些缺点-它会吞噬整个文件,并且它还没有在复杂数据上进行测试,替换标记以使用正确的标记可能会产生与预期不同的结果。
import yaml

def strip_malformed_directive(yaml_file):
    """
    Strip a malformed YAML directive from the top of a file.

    Returns the slurped (!) file.
    """
    lines = list(yaml_file)
    first_line = lines[0]
    if first_line.startswith('%') and ":" in first_line:
       return "\n".join(lines[1:])
    else:
       return "\n".join(lines)


def convert_opencvmatrix_tag(yaml_events):
    """
    Convert an erroneous custom tag, !!opencv-matrix, to the correct 
    !opencv-matrix, in a stream of YAML events.
    """
    for event in yaml_events:
        if hasattr(event, "tag") and event.tag == u"tag:yaml.org,2002:opencv-matrix":
            event.tag = u"!opencv-matrix"
        yield event


yaml.add_constructor("!opencv-matrix", lambda loader, node: None)
with open("test_0x.yml") as yaml_file:
    directive_processed = strip_malformed_directive(yaml_file)
    yaml_events = yaml.parse(directive_processed)
    matrix_tag_converted = convert_opencvmatrix_tag(yaml_events)
    fixed_document = yaml.emit(matrix_tag_converted)

    data = yaml.load(fixed_document)
    print data

原始回答

yaml.load 函数返回一个字典,可以这样访问:

import yaml

with open("test_0x.yml") as yaml_file:
    test_data = yaml.load(yaml_file)

print test_data["data"]

那有帮助吗?


我认为你没有抓住重点,即前两行不是有效的YAML代码,必须跳过。 - mhawke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接