Here’s one way to do it. Whether this is less ugly or not is probably a matter of opinion, but it is at least less visually repetitive.
\function convert.num() [regexp[\D]] :else[range{!!title}search-replace::regexp[\d],[.]]
<$let str="8x7x6x5x4x3x2x1">
{{{ [<str>split[]] :map:flat[convert.num[]] +[join[]] }}}
</$let>
Steps:
-
splitbetween each character - The filter with the
:mapprefix will be run once per input value. Since I needed a two-part filter to make use of the:elsecondition, I had to move both parts into the function/subfilterconvert.num, which becomes the sole content of my:maprun.- By default,
:mapruns yield one output per input value. The:flatsuffix switches it to a (potentially) one-to-many relationship, which will allow us to turn one digit into many periods. - I like functions, personally, but you could also do this with the
subfilteroperator, if you prefer. You’d need to make the following changes:-
\function convert.num()→\define convert.num() -
:map:flat[convert.num[]]→:map:flat[subfilter<convert.num>]
-
- By default,
- Now, looking at
convert.numitself…-
[regexp[\D]]= search for a non-digit. If this filter run returns any (non-digit) value, the rest of the function will be ignored, and the character is preserved as-is. -
:else…- use
rangeto generate a list of numbers beginning with 1 and ending with{!!title}(= the number). For instance,range[8]will give me1 2 3 4 5 6 7 8. - Use
search-replace::regexp[\d],[.]to replace each number in therangeoutput with a period.
- use
-
- Finally,
+[join[]]everything back into a single string.
And my generalized advice for long, ugly filters: if you find yourself reusing the same string of operators with different parameters, move it into a function instead!
Honestly, I might not have ordinarily bothered in a case like this, since your original is far more transparent at a glance and only ~30% longer. But this was a fun challenge, thanks!