Finding text (and selecting) within a text field

Hi all - new here and just getting to grips with things, so appreciate any help! I've bought KeyboardMaestro to attempt to speed up my Anki workflow for medical school. For those that don't know, it's basically a flashcard app for memorising things. As part of this app, I often need to change a single word in a text field that is encased with {{c1::xyz}} and {{c2::abc}} and so on and so forth. I'd like to create a macro for selecting the text within c1, c2 c3 etc by pressing control + 1, control + 2, etc. Effectively beginning selection at {{c1::then selecting everything up to}}, like I've underlined there.

Any help is appreciated! I tried using found image (which works great for finding a single cloze deletion) but I'm not sure how to extrapolate this into control + 1 etc without manually doing this for every possible cloze, or how to select until }} when the wrapped text is multiple words. Thanks a lot, and apologies in advance if this is a super simple thing!

Hi and welcome to the forum!

Can you post a screenshot?


Thanks for the response! Does this help?

I'll add that I think the solution is to simulate option + shift + right arrow, but just knowing it should start at the {{c1:: and finishing at the }} is something im struggling with

And do you want to select the text so you can type in, or can you pump the replacement text in from somewhere else? One-card-and-type hardly seems worth automating, but if you had a text file in the form

card1c1,card1c2,card1c3
card2c1,card2c2
card3c1,card3c2,card3c3,card3c4
etc

...it could be a real time-saver.

Thanks for the response! Yes it's so I can type in the selected field. This is something I do 100-500 times a day, so any time saving is worth it!

Wouldn't you save even more time if you could prepare the replacement text in advance? Or even just one card at a time? That may not be possible, but it should be quite simple to:

  • Select All in the "Text" field
  • Copy to the clipboard
  • Loop a regular expression that replaces {{cloopNumber::some text}} with {{cloopNumner::other words}}
  • Paste back into the "Text" field

I think it would actually be easier than "expanding the selection to the next '}}'"!

Yeah so this would be an elegant solution if I was able to prepare that far in advance, I make cards from lectures, question banks, textbooks etc so being able to do this on the fly is quite handy

Although it's usually my last resort, I reckon found images could work, as long as you're pretty precise. You may need to retake the screenshots and you'll almost certainly have to adjust each click offset so that the cursor lands just after the "::". Assuming that goes well, I've tested the highlighting part of this macro and it works.

I don't know of a better way to jump to a point in text I'm afraid, unless of course the app has a search function that you could automate...?

Select Term Inside "{{cx--________}}".kmmacros (77 KB)

Macro screenshot

1 Like

OK -- I took a wild stab and tried to include a KM variable in a regex. And it worked! @noisneil -- you might be able to do something with the following regex:

(?m)(\{\{c%Variable%Local_clozeCounter%::)([^\}\}]+)(\}\})
...replacing with:
\1%Variable%Local_replacementText%\3

...setting the two locals directly in the macro and using activate Anki/select all/copy/s&r on clipboard/paste steps.

@jpayne -- this will only work if you only have one of each closure in a text field (a quick skim of the Anki manual suggests you can have two or more of the same number, so they all reveal together). If that's the case then it is worth pursuing, using the hot key trigger value to set the cloze to work on and popping a dialog for you to enter the replacement text.

1 Like

Thanks! This is really helpful @Nige_S thank you also, but your solution seems much beyond my abilities haha! On that note, is there a particular programming language that is useful to learn for KM? I've done a few classes in Python

If it looks like it will work for you we might be able to run with it -- it would look much more understandable if posted in the usual macro or image format, but I can't move data between different machines at the moment to post.

There is, however, a huge gotcha. A quick test on the above shows that formatting is removed for all the copied text. I know that italics, sub- and superscripts, etc can be important in medical matters, so if you are using them in your cards (? -- never used Anki!) we will have to re-think.

Although, hopefully, one of the gurus might come up with a solution that retains any formatting!

Ok, I think this might be along the lines of what you had in mind. I must have misunderstood; I thought @jpayne wanted to replace the text inside the "{{cx--________}}". The regex replaces the whole thing. I couldn't get it to work with multiple occurrences of the cloze (new word to me!), but here's what I put together.

Edit: Weird. It worked before I added the Switch/Case, and now not so much... Testing testing...

Replace Cloze (Prompt).kmmacros (25 KB)

Macro screenshot

@Nige_S Just for my own info, what's the \1 and \3 doing in the replacement field?

1 Like

You missed the non-obvious \1 before and \3 after %Variable%Local_Replacement Text% -- totally my bad for typing it out because I can't send data out from my KM test machine at the moment. For completeness the replacement pattern would be:

\1%Variable%Local_Replacement Text%\3

Edit to add: regex collects "capture groups" between (...) that can be used later -- group 1 is (\{\{c%Variable%Local_clozeCounter%::), group 2 is ([^\}\}]+), group 3 is (\}\}) -- and we can use those in the replacement with \1, \2, and \3. We don't actually need the middle group in this case, so probably easier to leave it out altogether and search:

(?m)(\{\{c%Variable%Local_clozeCounter%::)[^\}\}]+(\}\})

replacing with:

\1%Variable%Local_replacementText%\2

I hope that explains it a bit. I'm more a spray'n'pray regexer than a pro!

1 Like

@Nige_S I did include the \1 and \3, and it wasn't working, so I tried deleting them, and forgot to replace them before I first uploaded. :man_facepalming:t2: I did actually re-upload with it corrected, but annnyway...

I replaced with the code you just supplied and, oddly, it worked on the "c2" variant (in the example @jpayne provided), but not the others. I figured out that it's because that one is at the end of a line. If I hit enter after each of the others to create a line break, it works with them too. Any idea why?

Replace Cloze (Prompt).kmmacros (25 KB)

Macro screenshot

Hi @noisneil - this is looking great! The only thing is, it doesn't seem to be working for me. I get the input box and I can tell it pastes (more entries in my clipboard manager), but the output is the same as the original text (e.g its effectively a copy-paste with extra steps currently). I'm not sure if this is something to do with the permissions on my computer (although I have granted KM all available in Privacy settings). I have trouble with other copy-paste addons just pasting the variable %URL%. Thanks for all your help! Feels like it's nearly there. Once it actually replaces the text, this is the exact function I'm looking for

@jpayne If you look at my most recent reply, you'll see that the version I posted there does work, but only when the cloze string is at the end of a line. Maybe @Nige_S will know why, as he's a bit more versed in regex than I am.

Actually, I think I'm just a bit faster at Googling :wink: I'll try and finish my macro when I'm back on my test machine, that'll make it easier to compare.

@jpayne -- you never said whether retaining text formatting was a requirement. I might have a way to do that. My Anki window looks different to yours, and has a button that shows the HTML "behind" the text. Does yours? If so, when your insertion point is in the "normal" view of the text field and you trigger HTML view, does the Tab key move the insertion point to the HTML and Cmd-A select the HTML (but not the "normal" text)?

Retaining formatting is useful but not 100% necessary (though if it would work that would be ideal). I use a slightly older version of Anki since I have many add-ons I depend on, but yes I can view the underlying HTML in the cards. I'm not sure what you mean about insertion point (sorry) but I think you could retain formatting by using a keyboard shortcut (built in or modified by an addon - either way it's possible) to switch to HTML view, copying then pasting back in HTML before returning to a "normal" text view.

Edit: I have tested this and it does indeed work (just added the Shift+Cmd+X shortcut at the start and end of the macro)

So here's my take -- you'll have to test against your own version of Anki and "deck" (is that what they're called?!).

Like @noisneil's it'll work on clozure n, where n is the number in your Hot Key Trigger -- I've only set up four, you can add another 6 (so 0 == 10) without changing the macro. If the insertion point isn't in a text field or you already have the HTML field open then the copied text (probably!) won't start with "

" and the macro will alert and exit.

Otherwise it replaces the text in your chosen clozure with whatever you enter in the dialog. Note that because we are using HTML you can use HTML tags in the replacement, eg "some < i >text< /i >" (without the extra spaces) to put "some text" on the card. The regex works with everything I've tested except if you have a "}" character in the text you want to replace, when it will fail silently and without changing the original text.

I'm sure there must be a better way of extracting the clozure number from the trigger, but this works! You could use AppleScript and UI Scripting to put/make sure the insertion point is in the right field at the start, but I'm assuming you'll be doing that manually, at least on the first card, and it'll stay positioned as you move from one to the next. I also don't like nuking the OS clipboard behind the user's back -- I guess you could work round that with Named Clipboards or similar, but I haven't got that far in my learning yet...

Anki Replacement Test.kmmacros (9.5 KB)

Summary

1 Like