如何在Perl中实现类似awk里next的跳过重启处理功能
Perl中实现类似AWK next命令的功能
AWK里的next命令作用是:停止处理当前输入记录,读取下一条记录并从程序第一个模式重新开始;到输入末尾时执行所有END规则。
现在想在Perl脚本的一系列转换规则里实现类似逻辑:比如下面的代码,希望在指定替换成功时,停止执行剩余规则,回到第一个规则重新处理:
s/a/A/g; s/b/B/g; next(); # 希望这里替换成功后跳回开头 s/c/C/g;
实际场景是处理ABC乐谱输入:
R: waltz M: 3/4 L: 1/4 K: C |: E2"C"G | d3"G7" | c2"C"G | F3"F" | E2"C"E | EFG | A3"Dm" | G3"G7" | | E2"C"G | d3"G7" | c2"C"G | F3"F" | E2"C"G | G"G7"AB | c3"C"- | c3 || ||d"G7" z/G/ G | BAG | E2"C"G | c3 | A2"F"c | d2"D"c | B3"G" | G3 | | E2"C"G | d3"G7" | c2"C"G | F3"F" | E2"C"G | G"G7"AB c3"C" | c3 :|
其中:
"C"、"Dm"、"G7"这类吉他和弦需要先替换,替换后跳过后续的音符处理E2、G、d3这类ABC音符要在while /re/gi循环中最后处理
之前尝试用next if s/".*?"/^$&/g;替换和弦,但直接跳过了所有音符替换,后续while循环没法执行,求最佳实现方式。
最佳实现方案
Perl里可以用redo结合循环块来实现这个需求——redo会让程序回到当前循环块的开头重新执行,正好匹配你想要的「替换成功后跳过剩余规则、回到第一个规则重新处理」的逻辑。
针对你的场景的具体代码示例
while (<>) { # 用命名块包裹所有转换规则,redo回到块的开头 RULES: { # 先处理吉他和弦替换,替换成功则redo回到开头,跳过后续音符处理 if (s/"([^"]+)"/^$1/g) { redo RULES; } # 处理音符替换(最后执行) while (/([A-Ga-g][0-9]*)/gi) { # 这里写你的音符替换逻辑,示例为给音符加括号 s/$&/[$&]/g; } } print; }
逻辑说明
- 用命名块
RULES包裹所有转换规则,方便redo精准跳转 - 优先处理和弦替换:如果替换成功,
redo RULES直接回到块的开头,跳过后面的音符处理逻辑,确保所有和弦都被优先处理完毕 - 只有当当前行没有和弦需要处理时,才会进入后续的音符替换循环
- 这种方式既保证了处理顺序,又不会跳过必要的音符处理步骤
为什么不用next?
Perl里的next是用于循环(如while/for),作用是跳过当前循环的剩余代码,直接进入下一次循环迭代(也就是处理下一条输入记录)。而你需要的是在当前记录内回到规则开头重新处理,不是跳到下一条记录,所以redo才是正确的选择。
内容的提问来源于stack exchange,提问作者xpt
相关产品推荐
相关产品推荐

