我正在尝试检测文本中的有效 Java 注释。这是我的测试程序(为了简单起见,我目前忽略了所有空格,稍后我将添加它):
txts = ['@SomeName2', # match
'@SomeName2(', # no match
'@SomeName2)', # no match
'@SomeName2()', # match
'@SomeName2()()', # no match
'@SomeName2(value)', # no match
'@SomeName2(=)', # no match
'@SomeName2("")', # match
'@SomeName2(".")', # no match
'@SomeName2(",")', # match
'@SomeName2(value=)', # no match
'@SomeName2(value=")', # no match
'@SomeName2(=3)', # no match
'@SomeName2(="")', # no match
'@SomeName2(value=3)', # match
'@SomeName2(value=3L)', # match
'@SomeName2(value="")', # match
'@SomeName2(value=true)', # match
'@SomeName2(value=false)', # match
'@SomeName2(value=".")', # no match
'@SomeName2(value=",")', # match
'@SomeName2(x="o_nbr ASC, a")', # match
# multiple params:
'@SomeName2(,value="ord_nbr ASC, name")', # no match
'@SomeName2(value="ord_nbr ASC, name",)', # no match
'@SomeName2(value="ord_nbr ASC, name"insertable=false)', # no match
'@SomeName2(value="ord_nbr ASC, name",insertable=false)', # match
'@SomeName2(value="ord_nbr ASC, name",insertable=false,length=10L)', # match
'@SomeName2 ( "ord_nbr ASC, name", insertable = false, length = 10L )', # match
]
#regex = '((?:@[a-z][a-z0-9_]*))(\((((?:[a-z][a-z0-9_]*))(=)(\d+l?|"(?:[a-z0-9_, ]*)"|true|false))?\))?$'
#regex = '((?:@[a-z][a-z0-9_]*))(\((((?:[a-z][a-z0-9_]*))(=)(\d+l?|"(?:[a-z0-9_, ]*)"|true|false))?(,((?:[a-z][a-z0-9_]*))(=)(\d+l?|"(?:[a-z0-9_, ]*)"|true|false))*\))?$'
regex = r"""
(?:@[a-z]\w*) # @ + identifier (class name)
(
\( # opening parenthesis
(
(?:[a-z]\w*) # identifier (var name)
= # assigment operator
(\d+l?|"(?:[a-z0-9_, ]*)"|true|false) # either a numeric | a quoted string containing only alphanumeric chars, _, space | true | false
)? # optional assignment group
\) # closing parenthesis
)?$ # optional parentheses group (zero or one)
"""
rg = re.compile(regex, re.VERBOSE + re.IGNORECASE)
for txt in txts:
m = rg.search(txt)
#m = rg.match(txt)
if m:
print "MATCH: ",
output = ''
for i in xrange(2):
output = output + '[' + str(m.group(i+1)) + ']'
print output
else:
print "NO MATCH: " + txt
所以基本上我所拥有的似乎适用于零个或一个参数。现在我尝试将语法扩展到零个或多个参数,如上一个示例所示。
然后,我复制了表示分配的正则表达式部分,并在第二组到第 n 组的前面添加了一个逗号(该组现在使用 * 而不是 ?):
regex = '((?:@[a-z][a-z0-9_]*))(\((((?:[a-z][a-z0-9_]*))(=)(\d+l?|"(?:[a-z0-9_, ]*)"|true|false))?(,((?:[a-z][a-z0-9_]*))(=)(\d+l?|"(?:[a-z0-9_, ]*)"|true|false))*\))?$'
但是,这不能工作。问题似乎是如何处理第一个元素,因为它必须是可选的,那么像第一个扩展示例 '@SomeName2(,value="ord_nbr ASC, name")'
这样的字符串将是接受了,这是错误的。我不知道如何使第二个到第 n 个分配仅取决于第一个(可选)元素的存在。
可以吗?是这样做的吗?您如何最好地解决这个问题?
谢谢
最佳答案
如果您只是想检测有效的语法,我相信下面的正则表达式将为您提供您想要的匹配项。但我不确定你在这些团体中做什么。您是否希望每个参数值也位于其自己的组中?这会更难,我什至不确定使用正则表达式是否可能。
regex = r'((?:@[a-z][a-z0-9_]*))(?:\((?!,)(?:(([a-z][a-z0-9_]*(=)(?:("[a-z0-9_, ]*")|(true|false)|(\d+l?))))(?!,\)),?)*\)(?!\()|$)'
如果您需要单独的参数/值,您可能需要为此编写一个真正的解析器。
编辑:
这是一个带评论的版本。我还删除了许多捕获组和非捕获组,以使其更易于理解。如果将其与 re.findall()
一起使用,它将返回两组:函数名称和括号中的所有参数:
regex = r'''
(@[a-z][a-z0-9_]*) # function name, captured in group
( # open capture group for all parameters
\( # opening function parenthesis
(?!,) # negative lookahead for unwanted comma
(?: # open non-capturing group for all params
[a-z][a-z0-9_]* # parameter name
= # parameter assignmentoperators
(?:"[a-z0-9_, ]*"|true|false|(?:\d+l?)) # possible parameter values
(?!,\)) # negative lookahead for unwanted comma and closing parenthesis
,? # optional comma, separating params
)* # close param non-capturing group, make it optional
\) # closing function parenthesis
(?!\(\)) # negative lookahead for empty parentheses
|$ # OR end-of-line (in case there are no params)
) # close capture group for all parameters
'''
阅读完您对参数的评论后,最简单的事情可能是使用上面的正则表达式来提取所有参数,然后编写另一个正则表达式来提取名称/值对以按照您的意愿进行操作。不过,这也很棘手,因为参数值中有逗号。我将把它作为练习留给读者:)
关于用于 Java 注释的 Python 正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10071295/