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

求助:awk脚本实现文本字符串提取替换时部分内容未生效

问题:修复AWK脚本的字符串替换异常

需求说明:解析文本文件,完成以下操作:

  • 提取双引号包裹且不含方括号的字符串S1
  • 将S1转为全大写生成常量定义S2,格式为public static final String 大写S1 = "S1";
  • 将所有S2插入文件顶部
  • 把原文件中所有的"S1"替换为对应的S2

示例输入(In.txt)

{
    put("legalName", "legalName");
    put("operName", "operName");
    for(int i = 0; i < 3; i++) {
        put("firstName["+ i + "]", "firstName[" + (i+1) + "]");
        put("lastName["+ i + "]", "lastName[" + (i+1) + "]");
    }   
}

期望输出(Out.txt)

public static final String LEGALNAME = "legalName";
public static final String OPERNAME = "operName";
{
    put(LEGALNAME, LEGALNAME);
    put(OPERNAME, OPERNAME);
    for(int i = 0; i < 3; i++) {
        put("firstName["+ i + "]", "firstName[" + (i+1) + "]");
        put("lastName["+ i + "]", "lastName[" + (i+1) + "]");
    }   
}

尝试过程与问题现象

最初使用的AWK命令

awk -F'"' '
{if ($2 != "" && $2 !~ /\[/) 
{print "public static final String " toupper($2), "= \"" $2 "\";"}}' In.txt

修改后的tst2.awk脚本

NR == FNR {
    arr[NR]=$0; 
    tailBeg = 1
    while ( match(substr($0,tailBeg),/"[[:alpha:]_][[:alnum:]_]*"/) ) {
        strBeg = tailBeg + RSTART
        strLen = RLENGTH - 2
        string = substr($0,strBeg,strLen)
        strings[string]
        locs[FNR] = locs[FNR] RS strBeg " " strLen
        tailBeg += (RSTART + RLENGTH - 1)
    }
    next
}
FNR == 1 {
    for ( string in strings ) {
        map[string] = toupper(string)
        printf "public static final String %s = \"%s\";\n", map[string], string
    }
    for (i = 1; i <= length(arr); i++) {
        for ( string in strings ) {
            map[string] = toupper(string)
            text = arr[i]
            gsub("\""string"\"", map[string], text)
        }
        printf "%s\n", text
    }
}

执行命令

awk -f tst2.awk In.txt In.txt > Out2.txt

异常现象

实际输出中部分符合条件的"S1"未被替换,例如第一个put("legalName", "legalName");里的"legalName"未替换为LEGALNAME,输出结果如下:

public static final String LEGALNAME = "legalName";
public static final String OPERNAME = "operName";
{
    put("legalName", "legalName");
    put(OPERNAME, OPERNAME);
    for(int i = 0; i < 3; i++) {
        put("firstName["+ i + "]", "firstName[" + (i+1) + "]");
        put("lastName["+ i + "]", "lastName[" + (i+1) + "]");
    }   
}

解决方案

问题根源:替换逻辑中,每次循环都重新赋值text = arr[i],导致只有最后一个字符串的替换生效(如operName),之前的替换结果被覆盖。

修复后的脚本(tst_fixed.awk)

NR == FNR {
    arr[NR] = $0;
    tailBeg = 1
    # 匹配所有双引号包裹的内容,后续过滤含方括号的项
    while (match(substr($0, tailBeg), /"[^"\[]*"/)) {
        strBeg = tailBeg + RSTART
        strLen = RLENGTH - 2
        string = substr($0, strBeg, strLen)
        # 仅保留不含方括号的字符串
        if (string !~ /\[/) {
            strings[string]
        }
        tailBeg += RSTART + RLENGTH - 1
    }
    next
}

FNR == 1 {
    # 输出所有常量定义
    for (string in strings) {
        map[string] = toupper(string)
        printf "public static final String %s = \"%s\";\n", map[string], string
    }
    # 逐行处理原文本,批量替换
    for (i = 1; i <= length(arr); i++) {
        text = arr[i]
        # 在同一行文本上依次执行所有替换操作
        for (string in strings) {
            gsub("\"" string "\"", map[string], text)
        }
        printf "%s\n", text
    }
}

关键修改点

  1. 调整匹配正则为/"[^"\[]*"/,确保能捕获所有双引号包裹的内容,再通过后续判断过滤掉含方括号的项,避免漏匹配
  2. 将text = arr[i]移到外层循环,确保每一行仅初始化一次,所有替换操作都在同一个text变量上执行,不会覆盖之前的替换结果

执行命令

awk -f tst_fixed.awk In.txt In.txt > Out.txt

执行后即可得到符合预期的输出,所有符合条件的"S1"都会被正确替换为对应的S2常量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:47:06