使用命名值通过pyparsing获取字符串中的令牌位置

时间:2018-11-07 01:14:32

标签: python pyparsing

使用pyparsing时,我试图获取字符串中的标记位置。我想报告C文件中包含卫士问题的位置:

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)

现在,当我得到比赛“ m”时,我可以得到m.guardname_define_value,最终我想要得到类似m.guardname_define_value.pos的东西,这是比赛在“线”中的位置。

我到达了这个question,这使我快到那里了,但是我不知道如何仍然使用令牌来获取命名范围?我不想使用魔术数字来获得比赛结束时的位置。

我对regex并不陌生,但是我对pyparsing并不陌生,并且对它的强大和清晰感到惊讶。真的很享受。如果上面我对我的工作有建议,我也会接受。

  1. 主要问题是获取带有命名结果的令牌位置,而不是使用幻数。例如:我不想做类似m.guardname_define_value[0][0]这样的神秘事情来获取职位
  2. 是否需要像上面一样尝试/捕获pp.ParseException?如果我不这样做,我会得到一个例外。我真的不在乎比赛是否失败,我还是只检查结果是否为无。
  3. 考虑到nestedExpr可能会满足我的要求,但是要好一步,我可以自动让它查找神奇匹配的#ifdef ... #endif? (也许开瓶器是“ #ifdef”,而开瓶器是“ #endif”吗?)
  4. 在不太贪婪的情况下说“寻找任何东西”的正确方法是什么?即此正则表达式:".*(FOO).*"会消耗并丢弃任何东西,直到找到并捕获FOO,然后再消耗并丢弃它之后的任何东西,我很难复制它。

谢谢。

1 个答案:

答案 0 :(得分:1)

这是您的示例代码,进行了一些细微修改。 (我真的不喜欢反斜杠,并且在脚本中嵌入文本样本时,您可能会发现使用三引号会更容易。)值得注意的是,我正在展示locatedExpr的用法。这可能是您真正想看到的。另外,请参见以下问题:Pyparsing: get token location in results name

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']