Convert hashtags found in text to tags

ive spent too much time before coming here to ask. ive changed database properties and my tags are not excluded.

ive also made sure that finder has the extra tags deleted.

can someone help me try to only make the conversion of my hashtags to tags for inside .md files ONLY. I don’t want the title names nor group names to become tags. I have already turned off those options in the settings. for some reason they still are created even when I pick the “convert hashtags to tags”

these are indexed files that I tag inside obsidian.

any help is extremely appreciated.

1 Like

Not sure whether there’s already a script for this but this one does what you want

--  Convert hashtags found in a Markdown record's text to tag

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

tell application id "DNtp"
	try
		set theRecords to selected records
		if theRecords = {} then error "Please select some records"
		show progress indicator "Creating Tags from Hashtags... " steps (count theRecords) as string with cancel button
		
		
		repeat with thisRecord in theRecords
			set theType to (type of thisRecord) as string
			if theType is in {"markdown", "«constant ****mkdn»"} then
				step progress indicator "... " & (name of thisRecord) as string
				set theText to plain text of thisRecord
				
				-- I didn't use a lookbehind assertation as it's probably better to remove the # afterwards in AppleScript
				set theHashTags to my regexFind(theText, "\\#(.*?)(?=\\s|$)")
				
				set theHashTags_clean to {}
				repeat with thisHashTag in theHashTags
					set thisHashTag to thisHashTag as string
					try
						set thisHashTag_clean to characters 2 thru -1 in thisHashTag as string
						set end of theHashTags_clean to thisHashTag_clean
					end try
				end repeat
				
				set tags of thisRecord to (tags of thisRecord) & theHashTags_clean
			end if
		end repeat
		
		hide progress indicator
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on regexFind(theText, thePattern)
	try
		set aString to current application's NSString's stringWithString:theText
		set {theExpr, theError} to current application's NSRegularExpression's regularExpressionWithPattern:(thePattern) options:0 |error|:(reference)
		set theMatches to theExpr's matchesInString:aString options:0 range:{0, aString's |length|()}
		set theResults to {}
		repeat with aMatch in theMatches
			set theRange to (aMatch's rangeAtIndex:0)
			set theString to (aString's substringWithRange:theRange) as text
			set end of theResults to theString
		end repeat
		return theResults
	on error error_message number error_number
		activate
		display alert "Error: Handler \"regexFind\"" message error_message as warning
		error number -128
	end try
end regexFind

1 Like

this works! however, only if you select the file itself, im trying to do it by indexed groups.

is there a way to allow #:scroll:/:scroll:_speakers to be known as a nested tag under
#:scroll: ? for some reason DEVONthink doesnt recognize it as a parent tag nor does it allow it to be a tag at all

It’s only possible to use a modified version of the script if you create a script library as it’s not possible to use the previous script from within a Smart Rule.

  1. Save this script to /Users/USERNAME/Library/Script Libraries/ (might be necessary to create this folder) and name it exactly Script Library - regexFind.scpt
-- Script Library - regexFind

use AppleScript version "2.7"
use framework "Foundation"
use scripting additions

on regexFind(theText, thePattern)
	try
		set aString to current application's NSString's stringWithString:theText
		set {theExpr, theError} to current application's NSRegularExpression's regularExpressionWithPattern:(thePattern) options:0 |error|:(reference)
		set theMatches to theExpr's matchesInString:aString options:0 range:{0, aString's |length|()}
		set theResults to {}
		repeat with aMatch in theMatches
			set theRange to (aMatch's rangeAtIndex:0)
			set theString to (aString's substringWithRange:theRange) as text
			set end of theResults to theString
		end repeat
		return theResults
	on error error_message number error_number
		activate
		display alert "Error: Handler \"regexFind\"" message error_message as warning
		error number -128
	end try
end regexFind

  1. Create a Smart Rule that searches Markdown records, this new script doesn’t check for the record type as it’s unnecessary in a Smart Rule.
-- Smart Rule script - Convert hashtags found in a record's text to tags (and create nested tags)

on performSmartRule(theRecords)
	tell application id "DNtp"
		try
			repeat with theRecord in theRecords
				set theText to plain text of theRecord
				
				-- I didn't use a lookbehind assertation as it's probably better to remove the # afterwards in AppleScript
				set theHashTags to script "Script Library - regexFind"'s regexFind(theText, "\\#(.*?)(?=\\s|$)")
				
				set theHashTags_clean to {}
				repeat with thisHashTag in theHashTags
					set thisHashTag to thisHashTag as string
					try
						set thisHashTag_clean to characters 2 thru -1 in thisHashTag as string
						if thisHashTag_clean does not contain "/" then
							set end of theHashTags_clean to thisHashTag_clean
						else
							create location (("/Tags/" & thisHashTag_clean) as string) in (database of theRecord)
							set end of theHashTags_clean to (item -1 of my tid(thisHashTag_clean, "/"))
						end if
					end try
				end repeat
				
				set tags of theRecord to (tags of theRecord) & theHashTags_clean
			end repeat
			
		on error error_message number error_number
			if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
			return
		end try
	end tell
end performSmartRule

on tid(theInput, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	if class of theInput = text then
		set theOutput to text items of theInput
	else if class of theInput = list then
		set theOutput to theInput as text
	end if
	set AppleScript's text item delimiters to d
	return theOutput
end tid


No idea, sorry.

Why are you obfuscating the values with emoji? This is not helpful when trying to determine if something is feasible or not.

what do you mean? the emoji for me means religion. which tells me that all of my files with that tag #:scroll: are religious. I don’t need words or letters with my emoji to tell me what it is.

in the obsidian program I use, this makes complete sense to do it this way for myself (my second brain).

or maybe I misunderstood your question?

@pete31 :
I do hope it´s permissable to jump into this thread.

background / motivation : I came here bec I am trying to find a solution to the problem that in DT the hashtag to tag conversion doesn´t allow for special characters in hashtags.
– now I need them bec

  1. for me it´s a way to simulate tag hierarchy w/in the flat #-hashtag-‘system’ /-syntax
  2. this becomes even more prevalent as some top-notch applications working around markdown are by now allowing (‘using’) these ‘non-standard’ hashtags as ‘standard’ (Bear, Diarly, NotePlan,…)

now: I tried using your scripts, Pete, in the hope / understanding they might allow for this kind of conversion spanning hashtags including special characters. got all done as you described but then received an error message from DT:
» „script “Script Library - regexFind” does not understand the message „regexFind“« (my translation from german)

so my two questions:

  1. would your script (or any other?!) allow for this kind of conversion of ‘non-standard hashtags’?
  2. … how can I make it work :-}

– thx a load in advance!
(would be really help the future-proof(er) chronicling of my life :-D)

Just a note: Future-proofing is best done by using standards, not special cases or implementations, i.e., ”App X does this; App Y does that”. You should carefully consider this.

2 Likes

No idea why but now I got the same error. When I tested before posting the scripts for @obadiahcruz it worked immediately, however now it was necessary to restart DEVONthink. Afterwards it works as expected.

The regex considers everything from # up to before the next whitespace (or end of text) as a hashtag. There are no limitations.

I’ve added a line that creates nested tags if necessary.

I’ve updated the script in the post above.

Actually DEVONthink/supports/hashtag/hierarchies, this example creates DEVONthink > supports > hashtag > hierarchies.

1 Like

Thanks Jim.
I was aware I´d trigger deep thinking when typing ‘future-proofing’ in times of earth collapse. I had second thoughts myself the very moment :slight_smile:

you are right to flag, what I was really going at was a certain scope of ‘future-proofing’ here.
I think by biography you are one of the people painfully aware that the search for a consistent metadata system between/above all the existing tools and metadata-systems is quite a recipe for pain, always and anyways.
– for me it is already a next-level proofing if I can get my lifelog in some usable form backuped via MD-files into DT – which I hope/conceive to be around for a while…
– but you are right, my prosumer approach really is some compromise btw. ‘universal standards’ (we know by now they can break down very easily these times) and my medium-term tool-ecology (relying on tools like Bear etc.) plus – my take of – the ‘soft-standards’ they set…
… and who knows what happens to the world once DT isn´t around anymore? or all those precious frogs inhabiting our planet now… maybe Archive.org will put some servers into space…?!

– but back to practicals: your thoughts are appreciated; and on a (certain) higher level you are surely right to flag this!
actually adding into this Christian Grünenbergs hint on the feasability of hashtag-hierarchies in DT, I might put this under some reconsideration (– though I do not know yet if this works with the envisioned Diarly - DT pipeline… and all the other apps I need in this…)
so thx!!

1 Like

thx Pete,

you are ever so helpful that it can only be acknowledged (and admired).
I will try again w/ new script!
and thx for the good news on the regex-front!!

appreciated! + best!
oliver

1 Like

hello Pete,

I think it´s my deep rooted ignorance (and semi-aversion) of scripting – but somehow DevonThink picks up on my bad energies, and still gives me the same error message.
I have

  • retried with a new copy of the script (just to be sure)
  • checked that I use correct naming of file (‘Script Library - regexFind’)

… any karmic hint or help you canpossibly spare with me on this one?

Did you restart DEVONthink afterwards?

hey Pete!

… sure did! :slight_smile:
– more than once :smiley:

No idea, sorry.

1 Like

@obadiahcruz does the script with the script library work for you? It does over here, but not for @lerone.

@obadiahcruz: thx also from my side for sharing of possible experiences! :slight_smile:

@pete31 @lerone

hello! just saw this. glad to help in the time of need! so what I did was create the script from scratch using apples built in script editor. and then manually added it into

/Users/obadiahcruz/Library/Application Scripts/com.devon-technologies.think3/Menu

(might want to put in your own username when searching in finder btw)

  • then I put it under the tags scripts folder.

that’s how ive been able to use the script with no issues at all

I honestly haven’t had the need to restart, sorry I can’t replicate that :confused: