解析yaml文件时跳过行

时间:2017-07-31 20:43:24

标签: python file parsing yaml argparse

我正在尝试创建一个脚本,您可以在其中导入yaml文件并验证它是否为yaml格式。我还希望它列出文件中的每个错误。我正在尝试做的是利用yaml安全加载,然后当它失败时打印错误消息,忽略该行,然后重新读取文件,并重复直到打印文件中的所有错误。导入文件时是否有一种简单的方法可以忽略行列表?继承了我目前的代码:

#Verify YAML modules is installed
try:
    import yaml
except:
    print ('You do not have the YAML module installed.\n'+'Run: pip install yaml to fix this' )
    quit()
#Verify argparse module is installed
try:
    import argparse
except:
    print ('You do not have the argparse module installed.\n'+'Run: pip install argparse to fix this' )
    quit()
import itertools
#Loop variable
i = 0

#Configuration for argument parsing
parser = argparse.ArgumentParser()
parser.add_argument("path", help='File/Directory path to be examined', type=str)
args = (parser.parse_args())

#The main loop
while (i == 0):
    skip = []
   #Loop to skip lines for re-iteration
    with open(args.path) as infile:
        for line in itertools.islice(infile, skip, None):
            #Verify file is in YAML, if so save as dict then end
            try:
                yml = yaml.load(txt, yaml.SafeLoader)
                print yml
                i == 1 
            #if not yaml record error seen, then redo the loop skipping previous errors
            except yaml.YAMLError as exc:
                print ("Error while parsing YAML file:")
                if hasattr(exc, 'problem_mark'):
                          mark = exc.problem_mark
                          print "Error position: (%s:%s)" % (mark.line+1, mark.column+1)
                          print exc
                          skip.add(mark.line+1)

2 个答案:

答案 0 :(得分:2)

为此,您必须自己编写完整的解析器。错误恢复只能由解析器正确实现,而不是在以后的阶段。我举一些例子说明为什么你的方法或任何其他解析后方法不起作用:

foo: | lorem
  ipsom dolor: - it amet

在这里,我们启动一个文字块标量但是在与指标|相同的行上开始内容。这是被禁止的。如果忽略第一行,您的YAML将如下所示:

  ipsom dolor: - it amet

这是一个YAML错误,因为您无法在冒号后启动紧凑序列。但等等 - 这个内容最初是在一个块标量内,所以它不会导致错误!

现在让我们来看看Anthon的提议,即跳过所有行,直到上一次缩进:

foo: !!map
  !!map {
    lorem: &a ipsum
  }
bar: *a

这里,第二个!!map是非法的,因为一个节点可能只有一个标签。因此,从第二个!!map开始删除所有行,直到找到与前一行(foo: ...)行相同缩进的行:

foo: !!map
bar: *a

您收到错误消息,告知您*a未引用锚点,因为您删除了包含锚点的行。但它也可以在没有锚点的情况下发生:

foo: {
    !!str !!str lorem: ipsum
  }
bar: baz

再次,删除行bar: baz

foo: {
bar: baz

现在你有一个无与伦比的{。我可以继续下去。实际问题在于语言理论:如果某个字符串包含一个YAML错误,则它不是有效的YAML字符串。您无法在其中找到“其他YAML错误”,因为没有定义的位置可以继续(在源中:我应该在解析器出错后继续解析哪个字符? at在出错之后我应该继续解析哪个州?)。

为了捕获后续错误,您需要在解析器中定义这些恢复点;您目前只是试图通过跳过内容来定义源中的恢复点,这还不够。

答案 1 :(得分:0)

WOOOT!我把它固定了!!!

Theres是一个很棒的工具,名为Yamllint,我可以利用它来完成我想要的工作:

#Verify YAML modules is installed
try:
    import yaml
except:
    print ('You do not have the YAML module installed.\n'+'Run: pip install pyaml to fix this' )
    quit()
#Verify argparse module is installed
try:
    import argparse
except:
    print ('You do not have the argparse module installed.\n'+'Run: pip install argparse to fix this' )
    quit()

try:
    import yamllint
except:
    print ('You do not have the yamllint module installed.\n'+'Run: pip install yamlint to fix this' )
    quit()
from subprocess import call
#call(["ls", "-l"])

#Configuration for argument parsing
parser = argparse.ArgumentParser()
parser.add_argument("path", help='File/Directory path to be examined', type=str)
args = (parser.parse_args())

#The main loop

#Verify file is in YAML, if so save as dict then end
ignore = set([])
with open(args.path, "r") as f:
    try:
        yml = (yaml.load(f))
        print yml
    #If not yaml run through yamllint
    except yaml.YAMLError as exc:
        call(["yamllint","-f","parsable",args.path])