如何用Perl高效实现DS代码系统中分类与代码名称的合并?
你的Perl脚本方案评估与正则问题解析
一、原始逐行脚本的高效性
你的第一个单行脚本其实是非常高效且适合这个需求的方案,原因如下:
- 流式处理,内存友好:它用
-n逐行读取文件,不需要把整个文件加载到内存中,哪怕处理几GB大的.mch文件也不会有内存压力。 - 逻辑简单直接:通过跟踪当前分类
$cat,遇到CODE行就输出分类+代码名称,没有复杂的正则回溯,执行速度快。 - 易维护:代码逻辑清晰,后续如果要修改格式或者增加处理规则,很容易调整。
完全没必要替换成更复杂的方案——这个脚本已经完美解决了你的需求,而且是最优解之一。
二、正则替换脚本的问题分析
你尝试的-0777全文件正则替换脚本,为什么只捕获每个分类下的最后一个代码名称?
核心原因是正则捕获组在重复匹配时会被覆盖:
你的正则里的(?:CODE \d (.*)(?s).+?(?-s))+是一个重复的非捕获组,其中的(.*)捕获组在每次匹配CODE行时都会更新它的值,当整个组匹配完成后,捕获组里只保留最后一次匹配到的内容,所以每个分类下只会输出最后一个CODE的名称。
三、如果一定要用全文件匹配的改进方案
如果你坚持想用一次性读取整个文件的方式处理,可以用循环匹配的方式,避免捕获组被覆盖的问题。比如下面的脚本:
perl -0777 -ne ' my $current_cat; # 遍历所有CAT和对应的CODE行 while (/ (?:^|\G) (?:CAT (\V+)\s*(?s).*?)? # 匹配分类,更新当前分类 CODE \d (\V+) # 匹配代码名称 (?s).*? # 跳过代码内容 /gx) { $current_cat = $1 if defined $1; # 遇到新分类就更新 print "$current_cat, $2\n" if $current_cat; } ' 'Mario Kart DS (USA).mch'
这个脚本用\G锚点来连续匹配,确保从上次匹配结束的位置继续查找,同时每次遇到CAT行就更新当前分类,遇到CODE行就输出对应内容,这样就能正确捕获每个分类下的所有代码名称。
不过还是要强调:原始的逐行处理脚本在性能和简洁性上都更优,除非有特殊需求,否则没必要替换。
内容的提问来源于stack exchange,提问作者noabody
相关产品推荐
相关产品推荐

