Perl/Regex to reparse .cht cheat file after changes

I found a couple of use cases where we [may] want to reparse a RetroArch .cht file. The first is if you edit/delete/rearrange a bunch of stuff but the format is correct and you just want to re-number everything.

Renumber .cht file contents:

perl -pe '++$a if /cheat\d+_desc/ ; s/(?<=cheat)\d+/$a/ ; s/(?<=cheat)(\d+)/$1-1/e' 'cheat.cht' | perl -0777 -pe 's/(?<=^cheats = )\d+(?=.*(?s).*cheat(\d+)(?-s))/$1+1/e' | perl -00pe0 > 'newcheat.cht'

It’s a trick that sets a counter variable each time cheat#_desc is encountered, then it looks for that # everytime it’s preceded by cheat and replaces it. The counter increments to 1, at the start, so we have to do the whole thing again while subracting 1 (since the first cheat is numbered 0).

After that, we ‘slurp’ the whole input file, matching cheats = # to the very last # in the file, and add 1. Finally, we strip extra EOL CR,LF, etc, out. It’s a nasty, dirty, misuse of Perl and Regex in a single line.

Here’s another one for ‘Nintendo DS’ cheats that have a ‘fake’ Category. This category is defined as a cheat#_desc not followed immediately by cheat#_code. Mario Kart DS (U).cht is a great example of this. Anyway, this bit of Perl will strip out the category names while combining them with the real cheat descriptions.

Merge DS categories and renumber .cht file contents:

perl -0777 -pe 's/(cheat(\d+)_)desc(?=.*\n(?!cheat\2_code))/\1cat/gi' 'cheat.txt' | perl -pe '$cat = $1 if s/^cheat\d+_cat = \"(.*)\".*\n// ; s/(^cheat\d+_desc = \")/$1$cat, / ; ++$a if /cheat\d+_desc/ ; s/(?<=cheat)\d+/$a/ ; s/(?<=cheat)(\d+)/$1-1/e' | perl -0777 -pe 's/(?<=^cheats = )\d+(?=.*(?s).*cheat(\d+)(?-s))/$1+1/e' | perl -00pe0 > 'newcheat.txt'

This code rewrites cheat#_desc not immediately followed by cheat#_code as cheat#_cat. The text of these is added to the cheat#_desc, for each virtual category, while removing the category itself. Then we just renumber everything as in the first piece of code.

1 Like

And we just ensure to start with cheat# and remove that redundant piece of code [doh!] to end up with.

Renumber:

perl -pe '++$a if /^cheat\d+_desc/ ; s/(?<=^cheat)\d+/$a-1/e' 'cheat.cht' | perl -0777 -pe 's/(?<=^cheats = )\d+(?=.*(?s).*cheat(\d+)_(?-s))/$1+1/e' | perl -00pe0 > 'newcheat.cht'

Merge category and renumber:

perl -0777 -pe 's/(cheat(\d+)_)desc(?=.*\n(?!cheat\2_code))/\1cat/gi' 'cheat.txt' | perl -pe '$cat = $1 if s/^cheat\d+_cat = \"(.*)\".*\n// ; s/(^cheat\d+_desc = \")/$1$cat, / ; ++$a if /^cheat\d+_desc/ ; s/(?<=^cheat)\d+/$a-1/e' | perl -0777 -pe 's/(?<=^cheats = )\d+(?=.*(?s).*cheat(\d+)_(?-s))/$1+1/e' | perl -00pe0 > 'newcheat.txt'