You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang解析Solidity代码时多行正则表达式匹配问题求助

解决Go中Solidity跨多行代码正则匹配问题

问题核心

Go正则默认不允许.匹配换行符,且跨多行的Solidity代码(如拆分多行的require)往往夹杂空格、注释,直接用单行正则会匹配失败。以下是两种针对性解决方案:


方案1:优化正则表达式(适合简单场景)

通过启用单行模式、处理空白字符、预处理移除注释,解决跨多行匹配问题:

关键步骤

  1. 启用单行模式:在正则开头添加(?s),让.匹配包括换行在内的所有字符;或直接用[\s\S](匹配所有空白/非空白字符,无需依赖模式)。
  2. 匹配任意空白:用\s*替代固定空格,适配换行、制表符、空格等任意空白组合。
  3. 预处理移除注释:避免单行/多行注释干扰正则匹配(比如注释内的括号、伪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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:50:38