2017-07-31 88 views
0

我试图创建一个脚本,您可以在其中导入yaml文件并验证它是否为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) 
+1

我不认为高层次的逻辑是合理的; yaml可以通过从其中删除一行来变得无法解析,因此您最终可能会遇到跳过该行并重新分析该文件的问题,从而无法验证。 – cowbert

+0

嗯,那么还有另一种方法来列出除此之外的文件中的所有yaml错误。我想我可以看到你的话。但让我们说第2行和第78行有问题,用我使用的安全加载方法会显示第2行的错误,然后停止。使用该脚本的用户基本上必须运行该脚本,修复1行,运行脚本,修复另一行,这比一次修复所有错误需要更长的时间(如果我能弄清楚如何一次显示它们) –

+1

@ VincentMorris您可以尝试跳过所有行,直到找到与错误发生前相同的缩进级别并从此处重新启动。这里有一些注意事项:1)你的错误指示器可能指示第1行,但实际的修正是几行前进2)SafeLoader不能加载带有标签的YAML 3)你使用的PyYAML有未修复的错误,在完美的YAML上抛出错误4)PyYAML仍然不支持YAML 1.2规范(从2009年开始)。 – Anthon

回答

2

为了这个工作,你必须自己编写完整的解析器。错误恢复是只能由解析器正确执行的事情,而不是在以后的阶段。我给你的,为什么你的方法或其他任何解析器后的做法是行不通的一些例子:

foo: | lorem 
    ipsom dolor: - it amet 

在这里,我们开始一个文字块标,但开始在同一行的指标|内容。这是禁止的。如果你忽略了第一线,你的YAML看起来像:

ipsom dolor: - it amet 

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

现在,让我们一起去安通的建议,跳过所有行,直到前一个缺口:

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

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

foo: !!map 
bar: *a 

你得到一个错误,告诉您*a没有引用一个锚,因为你删除包含锚点的行。但它也可能发生不主播:

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

同样,您删除的行,直到bar: baz

foo: { 
bar: baz 

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

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

0

WOOOT!我修好了它!!!

即使世界一个名为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])