我正在尝试在Groovy源文件上运行Clojure正则表达式来解析各个函数。
// gremlin.groovy
def warm_cache() {
for (vertex in g.getVertices()) {
vertex.getOutEdges()
}
}
def clear() {
g.clear()
}
这是我在Clojure中使用的模式:
(def source (read-file "gremlin.groovy"))
(def pattern #"(?m)^def.*[^}]")
(re-seq pattern source)
然而,它只抓住了第一行,而不是多行功能。
答案 0 :(得分:6)
作为演示如何从GroovyRecognizer
获取AST并避免尝试使用正则表达式解析语言的演示,您可以在Groovy中执行此操作:
import org.codehaus.groovy.antlr.*
import org.codehaus.groovy.antlr.parser.*
def code = '''
// gremlin.groovy
def warm_cache() {
for (vertex in g.getVertices()) {
vertex.getOutEdges()
}
}
def clear() {
g.clear()
}
'''
def ast = new GroovyRecognizer( new GroovyLexer( new StringReader( code ) ).plumb() ).with { p ->
p.compilationUnit()
p.AST
}
while( ast ) {
println ast.toStringTree()
ast = ast.nextSibling
}
打印出AST中每个GroovySourceAST节点的AST,给你(对于这个例子):
( METHOD_DEF MODIFIERS TYPE warm_cache PARAMETERS ( { ( for ( in vertex ( ( ( . g getVertices ) ELIST ) ) ( { ( EXPR ( ( ( . vertex getOutEdges ) ELIST ) ) ) ) ) )
( METHOD_DEF MODIFIERS TYPE clear PARAMETERS ( { ( EXPR ( ( ( . g clear ) ELIST ) ) ) )
你应该可以用Clojure的java interop和groovy-all jar文件做同样的事情
要获得更多信息,您只需要深入了解AST并稍微操作输入脚本。将上述代码中的while
循环更改为:
while( ast ) {
if( ast.type == GroovyTokenTypes.METHOD_DEF ) {
println """Lines $ast.line to $ast.lineLast
| Name: $ast.firstChild.nextSibling.nextSibling.text
| Code: ${code.split('\n')[ (ast.line-1)..<ast.lineLast ]*.trim().join( ' ' )}
| AST: ${ast.toStringTree()}""".stripMargin()
}
ast = ast.nextSibling
}
打印出来:
Lines 4 to 8
Name: warm_cache
Code: def warm_cache() { for (vertex in g.getVertices()) { vertex.getOutEdges() } }
AST: ( METHOD_DEF MODIFIERS TYPE warm_cache PARAMETERS ( { ( for ( in vertex ( ( ( . g getVertices ) ELIST ) ) ( { ( EXPR ( ( ( . vertex getOutEdges ) ELIST ) ) ) ) ) )
Lines 10 to 12
Name: clear
Code: def clear() { g.clear() }
AST: ( METHOD_DEF MODIFIERS TYPE clear PARAMETERS ( { ( EXPR ( ( ( . g clear ) ELIST ) ) ) )
显然,Code:
部分只是连接在一起的线条,所以如果粘贴回groovy可能不起作用,但是它们会让你知道原始代码......
答案 1 :(得分:3)
这是你的正则表达,而不是Clojure。您请求匹配def
,然后匹配任何内容,然后匹配一个不等于右括号的char。这个char可以在任何地方。你想要实现的目标是:(?sm)def.*?^}
。
答案 2 :(得分:2)
简短回答
(re-seq (Pattern/compile "(?m)^def.*[^}]" Pattern/MULTILINE) source)
来自http://docs.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html
默认情况下,正则表达式^和$忽略行终止符,并且仅分别匹配整个输入序列的开头和结尾。如果激活MULTILINE模式,则^在输入开始时和任何行终止符之后匹配,但输入结束时除外。当处于MULTILINE模式时,$匹配在行终止符之前或输入序列的结尾。
您需要能够传入
Pattern.MULTILINE
编译模式时。但是在re-seq上没有这个选项,所以你可能需要进入Java互操作才能使它正常工作?理想情况下,你真的应该能够在Clojure土地上指定它...... :(
更新:
实际上,它并不是那么糟糕。而不是使用正则表达式的文字表达式,只需使用Java interop作为您的模式。请改用(re-seq (Pattern/compile "(?m)^def.*[^}]" Pattern/MULTILINE) source)
(假设您已导入java.util.regex.Pattern)。我没有对此进行过测试,但我认为这样可以帮到你。