Some help with regex to modify clipboard content

I want to transfer my tasks in text form from one app to another and that is really easy to do with KM. However the text that I get contains certain characters that I wish to remove. Here is the macro I have right now, all I need is to make the regex edit :

This essentially copies a task from my 'today' or some other list in 2Do to Unclutter. The task I get from the app is often of the form :

'- (!) this is just a task copied (Today)'

I want to remove '- ' from the beginning and the trailing ' (Today)' at the end to only paste the text I need. However I want to remove the '- ' only if there is (!) or (!!) or (!!!) that follows it. Here are some examples :

  1. copied text : - (!) this is a task (Today)

  2. I want : (!) this is a task

  3. copied text : - this is a task (Today)

  4. I want : () this is a task

  5. copied text : - (!!!) this is a new task (Tomorrow)

  6. I want : (!!!) this is a new task

As you may have guessed, the explanation marks are responsible for priority of the task. There is also a starred projects that I also copy and their structure is as follows :

text I get to clipboard :

✮ work on a project (Today)

  1. do the first thing (2016-06-15)
  2. do this later (2016-06-15)
  3. then do this (2016-06-15)

I want to turn this to :

✮ work on a project

  1. do the first thing
  2. do this later
  3. then do this

I am very new to Regex and I am certain this should be pretty trivial to do but I found the examples provided on the internet for a solution to my problem quite huge and they didn't seem to work. I will appreciate any help on this. It would be amazing if it will work as I wish, I really want to learn regex.

Thank you a lot.

This might be what you're asking for. Let me know if I messed anything up.

Convert Task Text.kmmacros (6.5 KB)



This is amazing. Thank you Dan. I just realised how nice it would be to have multiple windows in Keyboard Maestro because right now I had to switch between your macro and mine and copy things. Would be cool if I could be able to split it and see two macros at the same time. Perhaps there is a good alternative to this that is also efficient. I will try to figure out how to remove the trailing dates when copying the whole project, with your macro and regex101’s help I should be able do it. Thank you again. :slight_smile:

You’re welcome!

One thing you could do, rather than have multiple windows open, is copy an action or actions and paste them into your macro. Then either use it like it is, or copy from the action that’s now in your macro. No switching needed.

I hope that makes sense. :slight_smile:

Regular expressions are way cool, but it’s taken me years and years to get to where I am now, and I’ve just barely broken the surface. I didn’t know about regex101 until a month or two ago. Would have been nice to know it earlier!

Have fun. Let us know if you need more help.

Never say never, but currently it would be a horrendous amount of work to make that happen (it just was not initially designed for that and that choice has been hammered home over many years, so it will take a lot of work to make multiple windows or some sort of split view).

Note that you can swap back and forth between two macros by clicking the recently edited history button (or the arrows).

I was playing a bit with regular expressions and with some help from a friend I made it work in here however I can't translate it to my KM macro. I can't just simply copy it as this does not work :

It works in regex101 though. What do I need to change in my regex to have it transfer to my KM macro nicely?

Thank you for any help.

I'm not sure if your issue is that the regex string in your image isn't the same as what's in the regex101 example, or that you're not sure how to do the replace. Perhaps both?

In any case, this works:

I copied the regex string from regex101 and pasted it straight into the "Regular expression" field in the Action. I used $1 as the replacement string.

Hope this helps!

Hey Dan,

I do not get the correct output for some reason, I copied your macro so it is identical and here is what I get :

I am not really sure what 'replace with $1' does here but I have tried it both ways, with it there and without it and in both ways the output is not what I want.

What am I doing wrong here?

You have it set to “String Matching (ignore case)” It needs to be “Regular Expression…” An easy mistake to make.

1 Like

I see, now it works in my 'test' macro, however translating it to the original macro that I want to have, it doesn't seem to work. :frowning:

Here is what I have :

But for some reason even though I have the same kind of string my clipboard, it doesn't modify the content in any way. Here is what I get :

Also I am still quite confused what is meant by '$1' in the 'replace' part? What does it reference to?

Not sure.

One thing you should always do is put a pause between a “Copy” action and accessing the clipboard. Pause for .3 seconds, or something like that. I doubt that’s your problem, though, but you never know.

There’s no mystery to how this works, once you got it working in the test code. So ask yourself what could be different, and test each assumption.

For example, put a “display text” right after getting the value from the clipboard. Is it the expected value?

Is it possible there’s some hidden characters in the text somewhere?

Did you type the name of the variable wrong somewhere?

Like I said, once it’s working in the test code, if you’re using the same input and regex action, then it has to work.

If you still have issues after looking at it for a while, select the actions in question, export them, post the file here, and I’ll look at it. Make sure you use the exact same actions as in your code, otherwise I’m not testing the right thing.

1 Like

Yes, you are right about the string being different.

This is the string that gets copied '- write some emails (Today)' with a delimiter on the next line like so :

My regular expression doesn't take that into the account. I have found this resource and am attempting to really get how to make use of these things but it is still a mystery for now.

Can you help me modify the regular expression so that I just get bare text out of it. Bitbar only accepts simple strings that it can pass into the menu bar.

Thank you a lot if you do decide to help me with it and for all the help you have given already. I actually really like how easy it is to debug code in Keyboard Maestro with various pauses and 'display text' popups.

Btw, just for context, I want to have a dynamic menu bar that I can pass in tasks that I want to do and I am so close to making it happen with your help. :smile:

Personally, I would get rid of the extra "return" doing this:

You could also try and put it in the regex string. It's usually "\n' (without the quotes). But it could also be "\r\n" (unlikely on a Mac, but possible).

I know all about using BitBar like this. If you have any questions, let me know, but start a new topic.

Firstly, something like:


is not a regular expression (or, well, technically it is, but not for what you think it is.

What it is is some sort of search and replace expression in some sort of language, one part of which (the bits between the first and second /) is a regular expression.

Keyboard Maestro is not a text language (like perl), it is a graphical language, so the “s/”, “/”, “/” parts that are not part of the regular expression are done graphically in the Search & Replace variable action.

Also, the replace part, the \1 you use there is not a regular expression, it is an indicator in the search & replace in that language that you wish to insert the first (1) capture group (bit that has brackets around it in the regular expression). In Keyboard Maestro, that is represented in the replace section with $1, not \1 (roughly have of systems with search & replace for regular expressions use \1 and half use $1 - that’s life for you unfortunately).

So, with that in mind you need to:

  • Use the Search & Replace variable action
  • Configured for Regular Expression searching
  • User the part between the first and second / as the regular expression
  • Use the part between the second and third / as the replace expression
  • Use $1 instead of \1
  • Understand about capture groups so you know what the $1 means.

Your test case had the (!!) at the start, the copied text does not. And since your regular expression matches against the ) character (ie a literal closing bracket) and that is not there, no match occurs.

1 Like

Thank you a lot Peter and Dan.

I managed to make it work with help of some IRC regex gurus :smile:

Here it is finalised and it works wonderfully :

display current 2Do task in BitBar.kmmacros (4.2 KB)

I have a small question.

Sometimes the string that comes in my clipboard can have multiple lines like this :

‘✮ make tea (Today)
use the new tea you ordered’

Since Bitbar only accepts one string to display, I want to have a conditional statement that checks if the string in the clipboard is one or two lines and if it is two lines, I guess I can split the string in two, so the above string will be split like so :

first string : ''✮ make tea (Today)'
second string : ‘use the new tea you ordered’

How can I make this split and also check if the original string that I get contains one or more lines?

Thank you a lot for any help.

The regex to match one or more line breaks would be [\r\n]+

“.” does not match line break characters.

So you can match against (.+)[\r\n]+(.+) to match two lines. And you can use the Search Variable action to get the results of the two capture groups to two variables. that action will fail if the search does not match, so you can turn off displaying and aborting for the failure, and test the %ActionResult% token after the failed search, or you can test for a match first and then do two different things based on one line or two. Ie, either:

  • if the variable matches (.+)[\r\n]+(.+)
    • Search Variable for (.+)[\r\n]+(.+) into Line 1 and Line 2
    • do stuff with both lines
  • Else
    • do stuff with one line


  • Search Variable for (.+)[\r\n]+(.+) into Line 1 and Line 2 - do not abort or notify on failure
  • if text condition %ActionResult% is OK
    • do stuff with both lines
  • Else
    • do stuff with one line

[smacks forehead] It was a long day… :slight_smile: