Golang解析Solidity代码时多行正则表达式匹配问题求助
解决Go中Solidity跨多行代码正则匹配问题
问题核心
Go正则默认不允许.匹配换行符,且跨多行的Solidity代码(如拆分多行的require)往往夹杂空格、注释,直接用单行正则会匹配失败。以下是两种针对性解决方案:
方案1:优化正则表达式(适合简单场景)
通过启用单行模式、处理空白字符、预处理移除注释,解决跨多行匹配问题:
关键步骤
- 启用单行模式:在正则开头添加
(?s),让.匹配包括换行在内的所有字符;或直接用[\s\S](匹配所有空白/非空白字符,无需依赖模式)。 - 匹配任意空白:用
\s*替代固定空格,适配换行、制表符、空格等任意空白组合。 - 预处理移除注释:避免单行/多行注释干扰正则匹配(比如注释内的括号、伪
require语句)。
代码示例
package main import ( "fmt" "regexp" ) // 移除Solidity中的单行/多行注释 func removeSolidityComments(content string) string { // 匹配多行注释 /* ... */ multiLineRegex := regexp.MustCompile(`/\*[\s\S]*?\*/`) content = multiLineRegex.ReplaceAllString(content, "") // 匹配单行注释 // ... singleLineRegex := regexp.MustCompile(`//.*$`) content = singleLineRegex.ReplaceAllString(content, "") return content } func analyzeFile(content string) { // 预处理:先清理注释 cleanedContent := removeSolidityComments(content) // 匹配跨多行的require语句:启用单行模式,适配括号前后的任意空白 requireRegex := regexp.MustCompile(`(?s)require\s*\(([\s\S]*?)\)\s*;`) matches := requireRegex.FindAllStringSubmatch(cleanedContent, -1) for _, match := range matches { fmt.Printf("匹配到require语句:\n%s\n", match[0]) fmt.Printf("内部内容:\n%s\n\n", match[1]) } } func main() { testSolidity := ` pragma solidity ^0.8.0; contract Withdraw { address public owner; constructor() { owner = msg.sender; } function withdraw() public { require( msg.sender == owner, // 检查调用者权限 "Only contract owner can withdraw" ); require( address(this).balance > 0, "No funds available" ); payable(msg.sender).transfer(address(this).balance); } } ` analyzeFile(testSolidity) }
方案2:使用Solidity AST解析(适合复杂场景)
正则无法处理嵌套括号、复杂表达式等情况,此时直接解析Solidity的抽象语法树(AST)是更可靠的方案:
代码示例(基于go-ethereum的Solidity解析库)
package main import ( "fmt" "github.com/ethereum/go-ethereum/solidity" "github.com/ethereum/go-ethereum/solidity/ast" ) func analyzeWithAST(content string) error { // 解析Solidity代码为AST tree, err := solidity.Parse(content, "") if err != nil { return err } // 遍历AST查找所有require调用 ast.Walk(tree, func(n ast.Node) bool { callExpr, ok := n.(*ast.CallExpression) if !ok { return true } // 判断是否是require函数调用 ident, ok := callExpr.Callee.(*ast.Identifier) if ok && ident.Name == "require" { fmt.Printf("找到require调用,参数数量:%d\n", len(callExpr.Arguments)) // 可进一步提取参数内容(如错误消息) for i, arg := range callExpr.Arguments { if strLit, ok := arg.(*ast.StringLiteral); ok { fmt.Printf("错误消息%d:%s\n", i, strLit.Value) } } fmt.Println("---") } return true }) return nil } func main() { testSolidity := ` pragma solidity ^0.8.0; contract Test { function execute() public { require( (msg.sender == owner) && (block.timestamp > deadline), "Permission denied or deadline exceeded" ); } } ` err := analyzeWithAST(testSolidity) if err != nil { fmt.Println("解析失败:", err) } }
方案选择
- 简单的跨多行检测(如无嵌套结构的
require):优先用优化后的正则,实现成本低。 - 复杂场景(嵌套表达式、自定义函数跨多行等):必须用AST解析,避免正则的局限性。
内容的提问来源于stack exchange,提问作者Fosfor
相关产品推荐
相关产品推荐

