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
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:
(() => {
'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