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

如何批量识别并修改代码库中的特定硬编码逻辑?

解决方案概览

针对15万份Python和Java代码文件的硬编码城市-国家映射迁移需求,核心分为三个步骤:静态代码分析识别目标模式、提取映射规则生成配置文件、批量替换原代码逻辑。以下是分语言的具体实现方案:


Python 代码处理方案

1. 识别硬编码模式

Python的目标模式包括直接函数调用比较、变量赋值后比较、三元表达式三种,使用AST(抽象语法树)分析能避免正则的误匹配问题。

示例代码(基于ast模块):

import ast

def extract_city_mapping_python(code):
    tree = ast.parse(code)
    mappings = {}
    # 跟踪存储get_city()结果的变量
    assigned_vars = {}
    
    for node in ast.walk(tree):
        # 记录变量赋值:如city = get_city()
        if isinstance(node, ast.Assign):
            for target in node.targets:
                if (isinstance(target, ast.Name) 
                    and isinstance(node.value, ast.Call) 
                    and isinstance(node.value.func, ast.Name) 
                    and node.value.func.id == 'get_city'):
                    assigned_vars[target.id] = True
        
        # 处理If语句
        elif isinstance(node, ast.If):
            if isinstance(node.test, ast.Compare):
                left = node.test.left
                city_val = None
                # 匹配get_city() == 'xxx'
                if (isinstance(left, ast.Call) 
                    and isinstance(left.func, ast.Name) 
                    and left.func.id == 'get_city'
                    and isinstance(node.test.comparators[0], ast.Constant)
                    and isinstance(node.test.comparators[0].value, str)):
                    city_val = node.test.comparators[0].value
                # 匹配city == 'xxx'(city是get_city()的赋值变量)
                elif (isinstance(left, ast.Name) 
                      and left.id in assigned_vars
                      and isinstance(node.test.comparators[0], ast.Constant)
                      and isinstance(node.test.comparators[0].value, str)):
                    city_val = node.test.comparators[0].value
                
                if city_val:
                    # 提取then分支的country赋值
                    for body_node in node.body:
                        if (isinstance(body_node, ast.Assign)
                            and any(isinstance(t, ast.Name) and t.id == 'country' for t in body_node.targets)
                            and isinstance(body_node.value, ast.Constant)
                            and isinstance(body_node.value.value, str)):
                            mappings[city_val.lower()] = body_node.value.value
                    # 提取else分支的默认值
                    for orelse_node in node.orelse:
                        if (isinstance(orelse_node, ast.Assign)
                            and any(isinstance(t, ast.Name) and t.id == 'country' for t in orelse_node.targets)
                            and isinstance(orelse_node.value, ast.Constant)
                            and isinstance(orelse_node.value.value, str)):
                            mappings['default'] = orelse_node.value.value
        # 处理三元表达式:country = 'India' if get_city() == 'Delhi' else 'US'
        elif isinstance(node, ast.IfExp):
            test = node.test
            left = test.left
            city_val = None
            if (isinstance(left, ast.Call) 
                and isinstance(left.func, ast.Name) 
                and left.func.id == 'get_city'
                and isinstance(test.comparators[0], ast.Constant)
                and isinstance(test.comparators[0].value, str)):
                city_val = test.comparators[0].value
            elif (isinstance(left, ast.Name) 
                  and left.id in assigned_vars
                  and isinstance(test.comparators[0], ast.Constant)
                  and isinstance(test.comparators[0].value, str)):
                city_val = test.comparators[0].value
            if city_val:
                if (isinstance(node.body, ast.Constant) 
                    and isinstance(node.body.value, str)):
                    mappings[city_val.lower()] = node.body.value
                if (isinstance(node.orelse, ast.Constant) 
                    and isinstance(node.orelse.value, str)):
                    mappings['default'] = node.orelse.value
    return mappings

2. 生成YAML配置文件

收集所有提取到的映射,合并去重后生成YAML:

import yaml

def generate_yaml_config(mappings, output_path='city_mapping.yaml'):
    default_val = mappings.pop('default', None)
    with open(output_path, 'w') as f:
        yaml.dump(mappings, f, sort_keys=False)
    # 追加默认值配置
    if default_val:
        with open(output_path, 'a') as f:
            f.write(f"'default': '{default_val}'\n")

3. 替换原代码逻辑

使用AST修改代码,将原有的if-else/三元表达式替换为配置读取逻辑:

import ast

def replace_python_code(code):
    tree = ast.parse(code)
    # 标记需要替换的节点
    nodes_to_replace = []
    assigned_vars = {}
    
    # 先遍历标记目标节点(逻辑同提取映射时的识别逻辑)
    # ...(省略重复的识别逻辑,仅标记需要替换的If/IfExp节点)
    
    # 构造新的代码节点
    new_code = """
data = yaml.safe_load(open('city_mapping.yaml'))
country = data.get(get_city().lower(), data.get('default', 'US'))
"""
    new_tree = ast.parse(new_code).body
    
    # 替换目标节点
    for node in nodes_to_replace:
        # 找到节点的父节点,替换子节点
        parent = None
        for n in ast.walk(tree):
            if node in getattr(n, 'body', []) or node in getattr(n, 'orelse', []) or node in getattr(n, 'values', []):
                parent = n
                break
        if parent:
            if isinstance(parent, ast.Module):
                parent.body = [new_tree[0], new_tree[1]] + [n for n in parent.body if n != node]
            else:
                # 针对函数内的节点替换
                if node in parent.body:
                    idx = parent.body.index(node)
                    parent.body[idx:idx+1] = new_tree
    
    return ast.unparse(tree)

Java 代码处理方案

Java使用JavaParser库进行AST分析,处理逻辑与Python类似,但需适配Java语法特性。

1. 识别硬编码模式

示例代码:

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

public class CityMappingExtractor {
    private static final Map<String, String> mappings = new HashMap<>();
    private static final String GET_CITY_METHOD = "getCity";

    public static Map<String, String> extractFromFile(File file) throws Exception {
        CompilationUnit cu = JavaParser.parse(file);
        mappings.clear();
        Map<String, Boolean> assignedVars = new HashMap<>();
        
        // 记录存储getCity()结果的变量
        cu.findAll(AssignStmt.class).forEach(assign -> {
            if (assign.getTarget() instanceof NameExpr) {
                NameExpr target = (NameExpr) assign.getTarget();
                if (assign.getValue() instanceof MethodCallExpr) {
                    MethodCallExpr call = (MethodCallExpr) assign.getValue();
                    if (call.getName().asString().equals(GET_CITY_METHOD)) {
                        assignedVars.put(target.getNameAsString(), true);
                    }
                }
            }
        });
        
        // 处理If语句
        cu.findAll(IfStmt.class).forEach(ifStmt -> {
            Expression condition = ifStmt.getCondition();
            String cityVal = null;
            if (condition instanceof BinaryExpr) {
                BinaryExpr binary = (BinaryExpr) condition;
                Expression left = binary.getLeft();
                Expression right = binary.getRight();
                // 匹配getCity().equals("xxx")
                if (left instanceof MethodCallExpr) {
                    MethodCallExpr call = (MethodCallExpr) left;
                    if (call.getName().asString().equals("equals") 
                        && call.getArguments().size() == 1
                        && call.getArguments().get(0) instanceof StringLiteralExpr
                        && call.getScope().isPresent()
                        && call.getScope().get() instanceof MethodCallExpr
                        && ((MethodCallExpr) call.getScope().get()).getName().asString().equals(GET_CITY_METHOD)) {
                        cityVal = ((StringLiteralExpr) call.getArguments().get(0)).getValue();
                    }
                }
                // 匹配city.equals("xxx")(city是getCity()的赋值变量)
                else if (left instanceof NameExpr 
                         && assignedVars.containsKey(((NameExpr) left).getNameAsString())
                         && right instanceof MethodCallExpr) {
                    MethodCallExpr call = (MethodCallExpr) right;
                    if (call.getName().asString().equals("equals") 
                        && call.getArguments().size() == 1
                        && call.getArguments().get(0) instanceof StringLiteralExpr) {
                        cityVal = ((StringLiteralExpr) call.getArguments().get(0)).getValue();
                    }
                }
            }
            
            if (cityVal != null) {
                // 提取then分支的country赋值
                ifStmt.getThenStmt().ifPresent(stmt -> {
                    extractCountryAssignment(stmt, cityVal.toLowerCase());
                });
                // 提取else分支的默认值
                ifStmt.getElseStmt().ifPresent(stmt -> {
                    extractCountryAssignment(stmt, "default");
                });
            }
        });
        
        // 处理三元表达式
        cu.findAll(ConditionalExpr.class).forEach(condExpr -> {
            Expression condition = condExpr.getCondition();
            String cityVal = null;
            if (condition instanceof BinaryExpr) {
                BinaryExpr binary = (BinaryExpr) condition;
                Expression left = binary.getLeft();
                if (left instanceof MethodCallExpr) {
                    MethodCallExpr call = (MethodCallExpr) left;
                    if (call.getName().asString().equals("equals") 
                        && call.getArguments().size() == 1
                        && call.getArguments().get(0) instanceof StringLiteralExpr
                        && call.getScope().isPresent()
                        && call.getScope().get() instanceof MethodCallExpr
                        && ((MethodCallExpr) call.getScope().get()).getName().asString().equals(GET_CITY_METHOD)) {
                        cityVal = ((StringLiteralExpr) call.getArguments().get(0)).getValue();
                    }
                }
            }
            if (cityVal != null) {
                if (condExpr.getThenExpr() instanceof StringLiteralExpr) {
                    mappings.put(cityVal.toLowerCase(), ((StringLiteralExpr) condExpr.getThenExpr()).getValue());
                }
                if (condExpr.getElseExpr() instanceof StringLiteralExpr) {
                    mappings.put("default", ((StringLiteralExpr) condExpr.getElseExpr()).getValue());
                }
            }
        });
        
        return new HashMap<>(mappings);
    }

    private static void extractCountryAssignment(Stmt stmt, String key) {
        if (stmt instanceof ExpressionStmt) {
            Expression expr = ((ExpressionStmt) stmt).getExpression();
            if (expr instanceof AssignExpr) {
                AssignExpr assign = (AssignExpr) expr;
                if (assign.getTarget() instanceof NameExpr 
                    && ((NameExpr) assign.getTarget()).getNameAsString().equals("country")
                    && assign.getValue() instanceof StringLiteralExpr) {
                    mappings.put(key, ((StringLiteralExpr) assign.getValue()).getValue());
                }
            }
        }
    }
}

2. 生成YAML配置

使用SnakeYAML库生成配置:

import org.yaml.snakeyaml.Yaml;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;

public class YamlGenerator {
    public static void generate(Map<String, String> mappings, String outputPath) throws IOException {
        Yaml yaml = new Yaml();
        try (FileWriter writer = new FileWriter(outputPath)) {
            yaml.dump(mappings, writer);
        }
    }
}

3. 替换Java代码逻辑

通过JavaParser修改AST,替换原逻辑为配置读取代码:

import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;

public class JavaCodeReplacer {
    public static void replaceCode(CompilationUnit cu) {
        // 导入YAML相关类
        cu.addImport("org.yaml.snakeyaml.Yaml");
        cu.addImport("java.util.Map");
        
        // 遍历所有方法,替换目标逻辑
        cu.findAll(MethodDeclaration.class).forEach(method -> {
            BlockStmt body = method.getBody().orElse(null);
            if (body == null) return;
            
            // 标记需要替换的IfStmt/ConditionalExpr节点(逻辑同提取映射时的识别)
            // ...
            
            // 构造新的代码语句
            String newCode = """
                Map<String, String> cityMapping = new Yaml().load(YourClass.class.getResourceAsStream("/city_mapping.yaml"));
                String country = cityMapping.getOrDefault(getCity().toLowerCase(), cityMapping.get("default"));
                """;
            body.getStatements().add(JavaParser.parseStatement(newCode));
            
            // 删除原有的目标节点
            // ...
        });
    }
}

大规模处理注意事项

  • 性能优化:使用多线程/进程遍历文件系统,避免单线程处理15万文件的卡顿。
  • 误匹配规避:严格限定目标函数名(get_city/getCity)和变量名(country),统一字符串大小写处理。
  • 备份与验证:批量修改前备份所有文件,人工抽查映射结果,修改后运行单元测试验证逻辑正确性。
  • 复杂场景兼容:处理多elif分支、嵌套if、不同字符串引号格式等场景。

内容的提问来源于stack exchange,提问作者Devavrata

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 15:00:45