使用命名值使用 pyparsing 获取字符串中的标记位置
Get token position in string with pyparsing, using named values
我试图在使用 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这样的东西,这是比赛的位置"lines".
我到达了这个 question,这让我快到了,但我不知道如何仍然使用标记获得命名范围?我不想使用幻数来获得比赛结束时的位置。
我对正则表达式并不陌生,但我是 pyparsing 的新手,我对它的强大和清晰感到非常惊讶。真的很享受。如果对我上面所做的有什么建议,我也会采纳。
- 主要问题是获取带有命名结果的标记位置,而不是使用幻数。例如:我不想做一些像
m.guardname_define_value[0][0]
这样神秘的事情来获得位置
- 我是否需要像上面那样 try/catch for pp.ParseException?如果我不这样做,我会得到一个例外。我真的不在乎匹配是否失败,我只是检查 None 的结果。
- 认为 nestedExpr 可能会做我想做的事情,但更进一步,我可以自动让它寻找神奇匹配的
#ifdef ... #endif
? (如果 opener 是“#ifdef”而 closer 是“#endif”?)
- "search for anything"又不过分贪心的正确说法是什么?即这个正则表达式:
".*(FOO).*"
会消耗并丢弃任何东西,直到它找到并捕获 FOO,然后再消耗并丢弃它之后的任何东西,我很难复制它。
谢谢。
这是您的示例代码,稍作修改。 (我真的不喜欢反斜杠,在您的脚本中嵌入文本示例时,您可能会发现使用三重引号更容易让人眼前一亮。)值得注意的是,我展示了 locatedExpr
的用法。这可能是你真正想看到的。另外,请参阅此 SO 问题: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']
我试图在使用 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这样的东西,这是比赛的位置"lines".
我到达了这个 question,这让我快到了,但我不知道如何仍然使用标记获得命名范围?我不想使用幻数来获得比赛结束时的位置。
我对正则表达式并不陌生,但我是 pyparsing 的新手,我对它的强大和清晰感到非常惊讶。真的很享受。如果对我上面所做的有什么建议,我也会采纳。
- 主要问题是获取带有命名结果的标记位置,而不是使用幻数。例如:我不想做一些像
m.guardname_define_value[0][0]
这样神秘的事情来获得位置 - 我是否需要像上面那样 try/catch for pp.ParseException?如果我不这样做,我会得到一个例外。我真的不在乎匹配是否失败,我只是检查 None 的结果。
- 认为 nestedExpr 可能会做我想做的事情,但更进一步,我可以自动让它寻找神奇匹配的
#ifdef ... #endif
? (如果 opener 是“#ifdef”而 closer 是“#endif”?) - "search for anything"又不过分贪心的正确说法是什么?即这个正则表达式:
".*(FOO).*"
会消耗并丢弃任何东西,直到它找到并捕获 FOO,然后再消耗并丢弃它之后的任何东西,我很难复制它。
谢谢。
这是您的示例代码,稍作修改。 (我真的不喜欢反斜杠,在您的脚本中嵌入文本示例时,您可能会发现使用三重引号更容易让人眼前一亮。)值得注意的是,我展示了 locatedExpr
的用法。这可能是你真正想看到的。另外,请参阅此 SO 问题: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']