gensub()能否接受函数调用作为第二个参数?及awk实践疑问
1. gensub()能否接受函数调用作为第二个参数?
直白点说:不能直接这么用。gensub的第二个参数是替换字符串,它会在正则匹配操作执行之前就被完整计算成一个静态字符串,而非每次匹配到目标内容时动态调用函数处理匹配结果。所以你把函数调用写在这里,函数只会执行一次,处理的是你传入的字面量参数,根本碰不到实际匹配到的内容。
2. 你的命令没达预期的核心原因
你踩了gensub的一个关键坑:替换字符串的计算时机早于匹配操作,具体拆解你的三次尝试:
第一次尝试:
gensub(/[aeiou]/,toupper("&"),"g")
这里的toupper("&")在gensub开始匹配前就运行了,"&"就是个普通字符串,toupper处理后还是"&"。而gensub里的&在替换阶段才代表匹配到的元音,相当于把每个元音替换成它自己,结果自然还是全小写的hello。第二次尝试:
gensub(/[aeiou]/,"&"toupper("&"),"g")
同样,toupper("&")先被计算成"&",替换字符串变成了"&&",gensub就把每个元音替换成两个自身,hello里的e变成ee、o变成oo,输出就是heelloo。第三次尝试:
gensub(/[aeiou]/,strtonum("&"),"g")strtonum("&")处理的是字面量"&",它不是有效数字,所以返回0。gensub把每个元音替换成0,结果就是h0ll0。
实现目标的正确写法
要完成“转全小写后仅元音大写”的需求,你需要在每次匹配到元音时动态处理,比如用循环结合match和字符串截取:
{ $0 = tolower($0) while (match($0, /[aeiou]/)) { # 截取匹配元音的前后部分,把元音转大写后拼接 $0 = substr($0, 1, RSTART-1) toupper(substr($0, RSTART, RLENGTH)) substr($0, RSTART+RLENGTH) } print }
测试输入HeLlO,会输出hEllO,完全符合你的预期。
内容的提问来源于stack exchange,提问作者Daemon Painter

