Regex search and replace: No captured group?

DT offers search/replace via Regex.

Is it possible to use captured groups in regex search/replace?

So in this: “DONE project migration to new platform”

  • Search: “^DONE (.*)$”
  • Replace: “$1 DONE”

I cannot seem to use “$1” for the captured group.

Any way to use captured groups?

Update

Thanks to StackOverflow I learned today that “sed” is indeed able to use group captures, but not via $1 for the first matching group pattern, $2 for the second etc, but by using \1 and \2, etc.

1 Like

The optional script available via the support assistant? Did you try \1?

How / where do I get that?

Btw looked in the Script for Regex replace. It uses Unix’ sed command. I can follow up on that and find a way, I think. Thanks for the previous hint (from my previous post to look into the scripts).

How did you try to use regex before installing this script actually?

Ah, yes, we were refering to the same script. I tried that already, and it does not work.The script uses the Unix command “sed” to do the regex replacement, and that seems not to be able to use “group captures”. Just confirmed in the terminal:

➜   echo "DONE project 1" | sed -E 's/^DONE(.*)$/$1 DONE/g'
$1 DONE
  • The text to change is “DONE project 1”
  • After the replace operation I should get “project 1 DONE”
  • But I get “$1 DONE”

You don’t use $1 for replacements. $ is for shell substitutions.

n=Jim; echo "Hi! My name is $n."

You’d use \1, \2, etc.

1 Like

Thank you Jim, you were fastern than me googling :slight_smile:

I append a version of Regex Rename in JavaScript. It doesn’t use sed and avoids some of its shortcomings. You have to use JavaScript regex syntax.

app = Application('DEVONthink 3');
app.includeStandardAdditions = true;

var sel = app.selection();

if (sel.length > 0) {
		var searchFor = app.displayDialog('Suchen nach RE', { defaultAnswer: "" });
		if (searchFor.textReturned === '') exit;
		var replaceWith = app.displayDialog(searchFor.textReturned + 
		    '\nErsetzen durch', { defaultAnswer: ""});
		var re = new RegExp(searchFor.textReturned);
        var reText = replaceWith.textReturned;
		sel.forEach( el => {
            var n = el.name();
			el.name = n.replace(re,reText);
		});
} else {
  app.displayAlert("Mindestens einen Datensatz auswählen");
}

1 Like

I’d like to know what “shortcomings” you are referring to.

I meant shortcomings of sed like character class abbreviations \d, \D, \s etc., non-capturing parenthesis, look-ahead/-behind, word boundaries (\b), non-greedy quantifiers.

Apparently, sed on Mac OS can use some of these features (though not all of them) if it is called with the -E flag. I don’t know if the script included with DT3 does use this flag, because the script editor doesn’t show me its source code. But I do know that I failed miserably in using this script to rename a document with capturing references etc. That was the reason I rewrote it in JavaScript.

1 Like

You’re welcome

Happened to me the other day. We need to write to a logfile what kind of renaming we did. Simple “Previous filename with full path(?) or UUID” and “New filename”.

Actually this is a very important info in a document management platform.

Is it possible to write to the DT log (window)? Or do we need to write in a seperate log file?

Like so?

(() => {
  let app = Application('DEVONthink 3');  
    app.logMessage('Moved file from A to B', 
	   {info: 'Renamed because old name was ugly'});
    })()

In AppleScript, you’d write

tell application id "DNtp"
   log message "Moved file from A to B" info "AppleScript version"
end tell

HTH

1 Like

We need to write to a logfile what kind of renaming we did.

I’m curious why you’d write to the Log window and again, who “we” refers to. You previously said the general group of users, but logging this kind of information wouldn’t be a broadly used action.

Hi Ugur,

you can actually log to files in the file system with either Apple- or JavaScript: https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/ReadandWriteFiles.html
May be that’s better than using DT3’s log window.

1 Like

I think I’ll pass the data to a Python script and log to a file from there. - Will post a how-to once I’m done.

DT is a document management system. And an operation that renames or changes lots of files irreversibly[1] should leave a trace somewhere. That is my understanding of a DMS. Or any complex system that I rely on.


  1. I renamed a few hundred files with a regex expression and made a mistake. Didn’t test the regex on dummy filenames (my mistake). Could not undo this operation. And had no log / trace whatsoever what the filenames were previously. Of course I had proper backups, but since DT has no file versioning or any other safety net, I think at least a log somewhere would be valuable. ↩︎

Why don’t you modify the script to cache the previous filename in an alias or comment or custom metadata?

This could also be done with a smart rule.

1 Like

Excellent. That’s a very good idea. Thank you.

You’re welcome :slight_smile: