Insert Characters Within The Text in a Variable

Hi all

I want to change a variable that always consist of 8 numbers, like:
12345678
into this:
12:34:56:78

of course, i could split (substring) the variable three times, into three new variables, and then construct a new variable by combining the three. But there must be a more elegant quicker nicer way :slight_smile:

Very easy if you know Regex, using the KM Search and Replace action with the "Regular expression" option:

Search For:
(\d\d)(?=\d)

Replace With:
\1:

Let us know if this works for you.

Ah! I knew it was that simple!
I didn't knew that there was a regex within search and REPLACE.

I would first think to do it like this:

but a non greedy version is even more elegant

In a real macro i would not search the text 12345678 of course, this is just an example.

In the future, please always provide real-world source text, and real-world example of desired results. This will save both of us a lot of time.

Please read:
Tip: How Do I Get The Best Answer in the Shortest Time?

Thanks, but this is NOT about using a non-greedy pattern.
It uses a positive look-ahead to require that one digit always follows the first two digits.

You've already been given a good solution there : -)

In case others come to this thread with contexts in which Keyboard Maestro Execute Script actions might be helpful, chunksOf (length N) is, as you intuit, a commonly needed pattern, which you can use to:

  • chunk a string or list into pieces of equal length (perhaps with a shorter one at the end, if the division has a remainder),
  • and rejoin the chunks by intercalating some new filler value

So for example, with Keyboard Maestro Execute Script actions, given a definition of chunksOf(n) for JavaScript, AppleScript, or Python, expressions like:

JavaScript

chunksOf(2)(
    Application('Keyboard Maestro Engine')
    .getvariable('sampleString')
).join(':');

AppleScript

tell application "Keyboard Maestro Engine" to ¬
    set sampleString to getvariable "sampleString"

intercalate(":", chunksOf(2, sampleString))

Python

':'.join(
   chunksOf(2)("$KMVAR_sampleString")
)

As in:

Chunks of length N.kmmacros (22.4 KB)

JS Source
(() => {
    'use strict';

    // --------------- CHUNKS OF LENGTH N ----------------

    const main = () =>
        chunksOf(2)(
            Application('Keyboard Maestro Engine')
            .getvariable('sampleString')
        ).join(':');


    // --------------------- GENERIC ---------------------

    // chunksOf :: Int -> [a] -> [[a]]
    const chunksOf = n => {
        // xs split into sublists of length n.
        // The last sublist will be short if n 
        // does not evenly divide the length of xs .
        const go = xs => {
            const chunk = xs.slice(0, n);
            return 0 < chunk.length ? (
                [chunk].concat(
                    go(xs.slice(n))
                )
            ) : [];
        };
        return go;
    };

    // MAIN ---
    return main();
})();
AppleScript Source
on run
	
	-- CHUNKS OF LENGTH N
	
	tell application "Keyboard Maestro Engine" to ¬
		set sampleString to getvariable "sampleString"
	
	
	intercalate(":", chunksOf(2, sampleString))
	
end run


------------------------- GENERIC ------------------------

-- chunksOf :: Int -> [a] -> [[a]]
on chunksOf(k, xs)
	script
		on go(ys)
			set ab to splitAt(k, ys)
			set a to item 1 of ab
			if {} ≠ a then
				{a} & go(item 2 of ab)
			else
				a
			end if
		end go
	end script
	result's go(xs)
end chunksOf


-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
	set {dlm, my text item delimiters} to ¬
		{my text item delimiters, delim}
	set s to xs as text
	set my text item delimiters to dlm
	s
end intercalate


-- splitAt :: Int -> [a] -> ([a], [a])
on splitAt(n, xs)
	if n > 0 and n < length of xs then
		if class of xs is text then
			{items 1 thru n of xs as text, ¬
				items (n + 1) thru -1 of xs as text}
		else
			{items 1 thru n of xs, items (n + 1) thru -1 of xs}
		end if
	else
		if n < 1 then
			{{}, xs}
		else
			{xs, {}}
		end if
	end if
end splitAt
Python Source for Execute Shell Script
/usr/local/bin/python3 <<PY_END 2>/dev/null

'''Chunks of length N (for strings and lists)'''


# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Chunks of N'''
    
    print(
       ':'.join(
           chunksOf(2)("$KMVAR_sampleString")
       )
    )
    
    
# ----------------------- GENERIC ------------------------
    
# chunksOf :: Int -> [a] -> [[a]]
def chunksOf(n):
    '''A series of lists of length n, subdividing the
       contents of xs. Where the length of xs is not evenly
       divible, the final list will be shorter than n.
    '''
    def go(xs):
        return (
            xs[i:n + i] for i in range(0, len(xs), n)
        ) if 0 < n else None
    return go


# MAIN ---
if __name__ == '__main__':
    main()
PY_END
1 Like

fantastic complexpoint!