Python 使用命名值通过pyparsing获取字符串中的标记位置

Python 使用命名值通过pyparsing获取字符串中的标记位置,python,pyparsing,Python,Pyparsing,我试图在使用pyparsing时获取字符串中的标记位置。我想在C文件中报告include guard问题的位置: import pyparsing as pp m = None n = None #a sample C header file lines = "\ #ifndef HEADER_FILE_H\n\ #define HEADER_FILE_H 1\n\ \n\ \n\ /* code is here */\n\ \n\ #endif /* HEADER_FILE_H */\ "

我试图在使用pyparsing时获取字符串中的标记位置。我想在C文件中报告include guard问题的位置:

import pyparsing as pp

m = None
n = None

#a sample C header file
lines = "\
#ifndef HEADER_FILE_H\n\
#define HEADER_FILE_H 1\n\
\n\
\n\
/* code is here */\n\
\n\
#endif /* HEADER_FILE_H */\
"

LBRACE,RBRACE,LBRACK,RBRACK,LT,GT,LPAREN,RPAREN,DQ,SEMI = map(pp.Suppress,'{}[]<>()";')
CIDENT = pp.Word(pp.alphanums + "_")  #any C identifier
LCOMMENT = pp.Suppress("/*")
RCOMMENT = pp.Suppress("*/")

last_line = lines.split("\n")[-1]  #get last line

pound = pp.Literal("#") + pp.Suppress(pp.Optional(pp.White(" \t")))
ifndef = pound + pp.Literal("ifndef")
ifnotdefined = pound + pp.Literal("if") + pp.Literal("!defined")
define = pound + pp.Literal("define")
endif = pound + pp.Literal("endif")
comment = pp.Optional(LCOMMENT + CIDENT("guardname_endif") + RCOMMENT)("guard_end_comment")

includeguardifndef = pp.Or([ifndef, ifnotdefined]) + pp.Optional(LPAREN) + CIDENT("guardname_ifndef_val") + pp.Optional(RPAREN)
includeguard = define + CIDENT("guardname_define_val") + pp.Optional(pp.Literal("1")("guard_is_one"))
includeguard_top = includeguardifndef + includeguard
includeguardendif = endif("includeguardendif") + comment

try:
   m = includeguard_top.parseString(lines)
except pp.ParseException:
   pass

try:
   n = includeguardendif.parseString(last_line)
except pp.ParseException:
   pass

print(m)
print(n)
将pyparsing导入为pp
m=无
n=无
#示例C头文件
行=”\
#ifndef头文件\u H\n\
#定义头文件\u H 1\n\
\n\
\n\
/*代码在这里*/\n\
\n\
#endif/*头文件*/\
"
LBRACE,RBRACE,LBRACK,RBRACK,LT,GT,LPAREN,RPAREN,DQ,SEMI=map(pp.Suppress,“{}[]”(“;”)
CIDENT=pp.Word(pp.alphanums+“”)#任何C标识符
LCOMMENT=pp.Suppress(“/*”)
RCOMMENT=pp.Suppress(“*/”)
最后一行=行。拆分(“\n”)[-1]#获取最后一行
pound=pp.Literal(“#”)+pp.Suppress(pp.Optional(pp.White(“\t”))
ifndef=磅+pp.Literal(“ifndef”)
ifnotdefined=pound+pp.Literal(“如果”)+pp.Literal(“定义”)
定义=磅+pp.Literal(“定义”)
endif=磅+pp.Literal(“endif”)
注释=pp.可选(LCOMMENT+CIDENT(“guardname\u endif”)+RCOMMENT)(“guard\u end\u comment”)
includeguardifndef=pp.Or([ifndef,ifnotdefined])+pp.Optional(LPAREN)+CIDENT(“guardname\u ifndef\u val”)+pp.Optional(RPAREN)
includeguard=define+CIDENT(“guardname\u define\u val”)+pp.Optional(pp.Literal(“1”)(“guard\u是一个”))
includeguard\U top=includeguardifndef+includeguard
includeguardendif=endif(“includeguardendif”)+注释
尝试:
m=includeguard\u top.parseString(行)
除pp.ParseException外:
通过
尝试:
n=includeguardendif.parseString(最后一行)
除pp.ParseException外:
通过
打印(m)
打印(n)
现在,当我得到匹配项“m”时,我可以得到m.guardname\u define\u value,最终我想要得到类似于m.guardname\u define\u value.pos的东西,这是匹配项在“行”中的位置

我做到了这一点,这让我几乎达到了目标,但我不知道如何仍然用标记获得命名范围?我不想在比赛结束时使用幻数获得位置

我对regex并不陌生,但我对pyparsing还不熟悉,对它的强大和清晰感到非常惊讶。真的很喜欢它。如果有人对我上面所做的事情提出建议,我也会接受

  • 主要问题是获取带有命名结果的令牌位置,而不是使用幻数。例如:我不想做一些像
    m.guardname\u define\u value[0][0]
    之类的神秘操作来获取位置
  • 我是否需要像上面那样尝试/捕获pp.ParseException?如果我不这样做,我会得到一个异常。我并不在乎匹配是否失败,我只是检查结果是否没有
  • 认为nestedExpr可能会实现我想要的功能,但更好的一步是,我可以让它自动查找神奇匹配的
    #ifdef…#endif
    (如果opener是'#ifdef',closer是'#endif'?)
  • “搜索任何东西”的正确说法是什么而不是太贪婪?例如,这个正则表达式:
    “*(FOO)。*”
    会消耗并丢弃任何东西,直到找到并捕获FOO,然后再消耗并丢弃任何东西,我很难复制它

  • 谢谢。

    这是您的示例代码,稍作修改。(我真的不喜欢反斜杠,在脚本中嵌入文本示例时,您可能会发现使用三重引号更容易。)值得注意的是,我展示了
    locatedExpr
    的用法。这可能是您真正想看到的。另外,请参见以下问题:


    1.通常,语法中不必包含
    White
    元素,pyparsing会隐式跳过空格。2.代码示例未运行,您遗漏了一些位,如LCOMMENT和RCOMMENT。(您还可以查看一些预定义的注释表达式,如
    cStyleComment
    cppStyleComment
    )3.您可以包括一些您试图解析的文本吗?4.搜索任何内容"可能是使用SkipTo处理的,不确定您正在解析什么。5.很高兴听到您的pyparsing体验是积极的,尽管存在一些挑战!谢谢@PaulMcG,我已经更新了一个更完整的示例,应该可以运行感谢@PaulMcG,我已经让它工作了,但我将仔细看看您在这里做了什么,并看看如何改进w我做了什么!
    import pyparsing as pp
    
    #a sample C header file
    lines = """
    #ifndef HEADER_FILE_H
    #define HEADER_FILE_H 1
    
    
    /* code is here */
    
    #endif /* HEADER_FILE_H */
    """
    
    LBRACE,RBRACE,LBRACK,RBRACK,LT,GT,LPAREN,RPAREN,DQ,SEMI = map(pp.Suppress,'{}[]<>()";')
    CIDENT = pp.Word(pp.alphas + "_", pp.alphanums + "_")  #any C identifier
    LCOMMENT = pp.Suppress("/*")
    RCOMMENT = pp.Suppress("*/")
    
    
    def make_directive(s, pound=pp.Literal("#")):
        return pp.Combine(pound + s, adjacent=False)
    
    ifndef = make_directive("ifndef")
    ifnotdefined = make_directive("if") + pp.Literal("!defined")
    define = make_directive("define")
    endif = make_directive("endif")
    
    comment = pp.Optional(LCOMMENT
                          + CIDENT("guardname_endif") 
                          + RCOMMENT)("guard_end_comment")
    
    
    includeguardifndef = ((ifndef | ifnotdefined) 
                          + pp.Optional(LPAREN) 
                          + CIDENT("guardname_ifndef_val") 
                          + pp.Optional(RPAREN))
    includeguard = (define 
                    + CIDENT("guardname_define_val") 
                    + pp.Optional(pp.Literal("1")("guard_is_one")))
    includeguard_top = includeguardifndef + includeguard
    includeguardendif = endif("includeguardendif") + comment
    
    # parse the header
    parser = includeguard_top + pp.SkipTo(includeguardendif).suppress() + includeguardendif
    print(parser.parseString(lines).dump())
    
    # parse the header, with locns
    loc = pp.locatedExpr
    parser = loc(includeguard_top) + pp.SkipTo(includeguardendif).suppress() + loc(includeguardendif)
    print(parser.parseString(lines).dump())
    
    ['#ifndef', 'HEADER_FILE_H', '#define', 'HEADER_FILE_H', '1', '#endif', 'HEADER_FILE_H']
    - guard_end_comment: ['HEADER_FILE_H']
    - guard_is_one: '1'
    - guardname_define_val: 'HEADER_FILE_H'
    - guardname_endif: 'HEADER_FILE_H'
    - guardname_ifndef_val: 'HEADER_FILE_H'
    - includeguardendif: '#endif'
    
    [[1, '#ifndef', 'HEADER_FILE_H', '#define', 'HEADER_FILE_H', '1', 46], [69, '#endif', 'HEADER_FILE_H', 95]]
    [0]:
      [1, '#ifndef', 'HEADER_FILE_H', '#define', 'HEADER_FILE_H', '1', 46]
      - guard_is_one: '1'
      - guardname_define_val: 'HEADER_FILE_H'
      - guardname_ifndef_val: 'HEADER_FILE_H'
      - locn_end: 46
      - locn_start: 1
      - value: ['#ifndef', 'HEADER_FILE_H', '#define', 'HEADER_FILE_H', '1']
    [1]:
      [69, '#endif', 'HEADER_FILE_H', 95]
      - guard_end_comment: ['HEADER_FILE_H']
      - guardname_endif: 'HEADER_FILE_H'
      - includeguardendif: '#endif'
      - locn_end: 95
      - locn_start: 69
      - value: ['#endif', 'HEADER_FILE_H']