Search and Replace with RegEx in Clipboard

Hi,

I am trying to get some annoying tasks less tedious, and often this involves replacing parts of some text string and putting it back. :slight_smile:

I keep running into small issues in how Keyboard Maestro deals with the regex (I'm not very good at it, so it's probably me) and was wondering if anyone could assist in a seemingly small but rather important part.

If I create a regex to capture some groups, and then I want to replace one of those groups I run into problems.

Example:

Search for: (somestring)(\d*)

Now I want to replace the 2nd Captured Group with a specific number instead of whatever is there.

In several text editors where I've tested this I can use the following replace statement: ${1}1000

This results in getting "somestring1000" added. The {} isolates the captured group and lets me combine it with a string. However, if I do this in Keyboard Maestro it doesn't work. I've tried other characters, and I've tried using named groups, but nothing seems to work. The result is always the actual "string" I've got in the "replace with". So it replaces with for instance "${1}1000" instead of "somestring1000".

I'm sure this is some stupid oversight on my part, but any advice would be really appreciated!

EDIT: I use TextMate as my primary Text Editor for these kinds of things, and it supports the samples mentioned above.


[Moderator's Note: @peternlewis has accepted a feature request for the next major version of Keyboard Maestro. See:]

This is NOT at all a stupid question. It is an excellent question.
After some research and trial/error, I can ==confirm your behavior that the below RegEx works in some tools (Regex101.com in this case), but not in KM:==

RegEx101.com -- Works

image

SEARCH:
(?<PREFIX>somestring)\d*

REPLACE:
${PREFIX}1000

See regex101: build, test, and debug regex

In KM, the result is:

image

image


@peternlewis: Are we missing something, or is this a bug in KM?

Per the ICU Regular Expressions that KM uses, this should work:
${NamedGroup}

1 Like

Keyboard Maestro does not support replacement of named capture groups.

Thanks for clarifying. But is there any form of support for combining numbered groups and strings in a replacement though? Because ${1} won’t work either - which is also supposed to work according to ICU.

And if I want to replace the number following some string, without any special encapsul of the number of the group, it won’t recognize the group.

So in my sample $1 (representing the ‘somestring’) and ‘1000’ can’t be written as $11000 as that is read as an attempt to target an undefined group resulting in it just being replaced with the string ‘$11000’.

If there’s no way to isolate a captured group in a replacement, I guess I’ll need to go the way around by splitting the captures groups into variables, and then combining the variables I want with the strings I want. So it’s doable. I guess I could also write some script and call that with the KM Macro.

So I went with the method I outlined in the reply above. I've setup a Search Action using Regular Expression where the whole string is captured into different groups and stored in variables, then I reassemble a new string using the needed variables and a string instead of the variable of the captured group I want to replace, and push it back to the clipboard.

Problem solved, but good to know that this is the way to go about these use cases.

Hey @peternlewis,

Would you please explain why in brief, since they're part of the ICU RegEx specification.

Is this a limitation of Keyboard Maestro, or is this a limitation of the macOS' implementation of ICU RegEx?

TIA.

-Chris

1 Like

Hey @herrevjan,

This is a nutty problem that should not exist – nevertheless it does, so we need a viable workaround.

The easiest way I can think of to deal with it in the Keyboard Maestro UI is to make two passes.

Search:

(somestring)(\d*)

Replace:

\1•1000

Make a second search/replace pass to remove the bullet (or other non-used character).

I often use the Modifier Letter Circumflex Accent ‘ˆ’, because it is almost never found in isolation in any text. (Note that it's very different than the Circumflex Accent or Caret Character ‘^’.)

It's also quick and easy to obtain from any keyboard: I

I tend to test with bullets though, because they're very easy to see.

-Chris

2 Likes

Both.

macOS implementation of [NSRegularExpression stringByReplacingMatchesInString:options:range:withTemplate:] (at least in High Sierra) does not support anything except $0…$n.

Also, Keyboard Maestro, which implements its own match replacement (to allow things like expanding tokens multiple times differently as well as \n or $n) does not implement ${name} either.

And yes, Keyboard Maestro considers $1000 to be a reference to the 1000’th capture group, and does not support ${1} so there is no direct easy workaround for this, although a simple solution assuming there is any character that you can guarantee does not appear in the string (I usually use bullets (•) for this purpose) is to add the character in to the replacement ($1•000) and then use a second Search & Replace to remove all the • characters. If you can't guarantee such a character you can use a string like “•KMDEL•”.

2 Likes

This is done for the next version (still a long time away, so don't ask “when?”).

  • ${nnn} is supported, replaces with the respective capture group, or “${nnn}” is there is insufficient capture groups.
  • \n (single digit n only) replaces with the respective capture group, or “\n” is there is insufficient capture groups
  • $nnn replaces with the respective capture groups. If there is less than 10 capture groups, then $123 will replace with the first capture group, followed by “23”. If there were at least twelve capture groups, then it would be the 12th capture group, followed by “3”
  • ${name} replaces with the respective named capture group, or “${name}” if there is no such named capture group. This required 10.13+. Name must start with an ASCII letter, followed by zero or more ASCII letters and numbers.
5 Likes