Could you help me filter and renumber a list?

I made a macro that lets me select presets on a guitar pedal via MIDI (video below). At the moment I'm getting the preset names by copying each line to a variable on a loop, in the pedal's editor software. It's clunky and I have to redo it any time I change my preset order.

Some clever chap made a python tool which will read a presets backup file and spit out the preset list.

Example Preset Info

Local__HXPresetList =

Device: 2162694
Version: 3.15
Backup Date: Thu Mar 24 12:52:08 2022
Description: None
Set List #1: PRESETS
Used: 126/126
Available: 0/126
IRs: 52
01A MIDI
01B Model D
01C Ampeg B15 Auto
02A Ampeg B15 LoPass
02B UAD Guitar
02C UAD SVTVR
03A Princeton
03B Looper
03C Shuffle-Looper
04A Deluxe
04B Deluxe Sustainer
04C Deluxe Breakup
05A Deluxe Dirty
05B AC 30 ss
05C JTM45
06A Plexi
06B Super Reverb
06C Bassman
07A Tweed
07B Twin
07C Modern Twin
08A Twin Comp
08B Twin mod/delay
08C Twin Squish
09A Funk Twin
09B Funk DI
09C Carol Kaye
10A Star Spangled
10B Widdle
10C Tweed Dlx Boxy
11A Tweed Dlx Growl
11B Auto-Wah
11C Ego Auto Mix
12A Ego Latch Wet
12B Ego Octave
12C Benson
13A Jazz Chorus ss
13B Wobbly 1
13C Wobbly 2
14A Ambi Band
14B Ambi Swell
14C Surf Spring
15A Sex Pistols
15B Isley Fuzz Phase
15C Zvex / Muff
16A 80s Chorus
16B Edge ss
16C Scofield Volume
17A Scofield Wah
17B Sco Whammy ss
17C Tom Morello ss
18A The Who
18B Led Zep Supro ss
18C Angus 70s
19A Angus 80s
19B Angus 90s
19C Slash
20A Queen
20B Queen Lead
20C Queen Harm: Cmaj
21A Paul Gilbert
21B Van Halen
21C Steve Vai
22A Yngwie Hall
22B Yngwie Room
22C Metal Chug
23A Low B Chug
23B Tight Rhythm
23C Jangly DI
24A Synth
24B Baritone
24C Whammy
25A DIR:AlwysSatchJS
25B DIR:2/3 Beards
25C DIR:ANGL Meteor
26A DIR:Badonkulous
26B DIR:Brown Sugar
26C DIR:BrownGD
27A DIR:CaliRectifre
27B DIR:Cartographer
27C DIR:Derailed
28A Cmin Pent Gallop
28B DIR:Essex A30
28C DIR:Glossary
29A DIR:Heartbreaker
29B DIR:Htl CaliJS
29C DIR:JBeckLversJS
30A DIR:Litigator
30B DIR:Mandarin 80
30C DIR:RelativityGD
31A DIR:Relief
31B DIR:Seared GuyJS
31C DIR:Steely KidJS
32A DIR:Teh Br00talz
32B DIR:VH JumpJS
32C DIR:VintageGD
33A BAS:Busy One Ch1
33B BAS:Cali 400 Ch1
33C BAS:Del Sol 300
34A BAS:SVT Nrm
34B BAS:SVT-4 Pro
34C BAS:TyK0 Like
35A Herbie Bubbles
35B Sustain Swell
35C New Preset
36A New Preset
36B New Preset
36C New Preset
37A New Preset
37B New Preset
37C New Preset
38A New Preset
38B New Preset
38C New Preset
39A New Preset
39B New Preset
39C New Preset
40A New Preset
40B New Preset
40C New Preset
41A New Preset
41B New Preset
41C New Preset
42A New Preset
42B New Preset
42C New Preset

To make it usable in my macro, I need to delete the stuff at the top (up until 01A) and delete the empty presets (lines which contain "New Preset"). Finally, I need to replace the numbering system (more on that below).

After much trial, error, copying and pasting, I found a regex code that removes every line containing a string:

[^\r\n]*New Preset[^\r\n]*([\r\n]+|$)

This removes the empty presets for me. Happy days.

I don't know how to delete everything up until "01A", or how to simply to delete the first eight lines, so opted for a regex code that deletes the top line and repeats it eight times. This is probably a sub-optimal method, but it works. Happy-ish days.

Now for the tough bit. I'd like to remove the 01A/01B/01C... numbering system and replace it with 1/2/3..., which is how it appears on the pedal itself. I suppose this would involve deleting the first three characters of every line, which I've tried and failed thus far to do. The renumbering part I have no idea about.

Any advice on how to achieve this last step, as well as any refinements I could make on the previous two, would be really great. Thanks!

159723372-076ade68-5121-4223-aaa2-29976dd870be

1 Like

Something like this ?

Filtered and renumbered presets.kmmacros (5.4 KB)

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    const main = () => unlines(
        lines(
            Application("Keyboard Maestro Engine")
            .getvariable("presetList")
        )
        .filter(
            s => isDigit(s[0]) && (
                !s.endsWith("New Preset")
            )
        )
        .map(
            (s, i) => `${1 + i} ${unwords(words(s).slice(1))}`
        )
    );


    // --------------------- GENERIC ---------------------

    // isDigit :: Char -> Bool
    const isDigit = c => {
        const n = c.codePointAt(0);

        return 48 <= n && 57 >= n;
    };


    // lines :: String -> [String]
    const lines = s =>
        // A list of strings derived from a single
        // string delimited by newline and or CR.
        0 < s.length ? (
            s.split(/[\r\n]+/u)
        ) : [];


    // unlines :: [String] -> String
    const unlines = xs =>
        // A single string formed by the intercalation
        // of a list of strings with the newline character.
        xs.join("\n");


    // unwords :: [String] -> String
    const unwords = xs =>
        // A space-separated string derived
        // from a list of words.
        xs.join(" ");


    // words :: String -> [String]
    const words = s =>
        // List of space-delimited sub-strings.
        s.split(/\s+/u);

    return main();
})();

The problem is how to filter and renumber a list ?

"Regex" in a thread title usually expresses an XY difficulty:

1 Like

I don't see this as a regex problem, especially the line numbering part. Try this:

Adjust MIDI.kmmacros (4.1 KB)

Image of macro

It takes your Local_HXPresetList variable and outputs

001 MIDI
002 Model D
003 Ampeg B15 Auto
004 Ampeg B15 LoPass
005 UAD Guitar
006 UAD SVTVR
007 Princeton
008 Looper
009 Shuffle-Looper
010 Deluxe
011 Deluxe Sustainer
etc.

via a short Perl script.

The output differs in two ways from your example:

  1. The numbering starts at 1, not 0. If you want to change it to 0, change the $. - 8 to $. - 9 in the printf line.
  2. I put leading zeros in the numbers so the names line up. If you don't want that, change the %03d to %d in the printf line.

Update
I suppose I should have refreshed the page before posting. @ComplexPoint had the same idea, and I'm sure his solution is similar.

1 Like

First of all, @ComplexPoint and @drdrang, can I just say thankyou so much for getting back to me so quickly with two different and equally effective solutions. Very kind of you both! If I could mark them both as the solution I would.

I apologise for the erroneous title. I'm slowly learning of the seemingly infinite ways you can do things.

To wit, @drdrang, I'm staring at five lines of code and wondering how in the heck it can do everything so efficiently. I mean it's all greek to me, but I'm still mightily impressed!

On the slim chance someone might also like to load presets on a Line 6 Helix device from a searchable pop-up list, here are my macros.

Thankyou both once again.

HX - Search Presets.kmmacros (102.3 KB)

HX - Backup & Get Presets - Screenshot

HX - Search Presets - Screenshot

1 Like