162 151 150 bytes
- -11 bytes thanks to my idea of using
load instead of
- -1 byte by omitting newline
l,p=...print(((math.ceil(load('return '..p:gsub('.',load'n=l:find(...,1,1)return n and n-1'))()-0.5)..''):gsub('%d',load'c=...+1 return l:sub(c,c)')))
Try it online!
Not shortest thing in the world (Lua forces you to be fancy quite hard, especially by huge keywords), but was pretty fun to create. Full program taking input as arguments and printing result.
Assign values from arguments to variables. Our dictionary is
l and expression is
Following expression is quite hard to understand because it have a weird order of execution, so I'll explain it step-by-step:
Converting to normal numbers
load'n=l:find(...,1,1)return n and n-1')
Perform replacement on expression string: take each symbol and pass it to function (
load proved itself to be shorted than normal declaration here).
Function finds position of occurrence in dict string for passed symbol using
... is first (and only) argument here as we're in vaarg function (any
loaded one is) that is our current symbol. Following arguments are required to make
find ignore special symbols (
1 is just short value which evaluates as
true when converted to boolean): starting position (one is default here) and
plain, which actually disables pattern handling. Without those program fails on third test case due to
% being special.
If match is found, subtract one as Lua strings (and arrays btw) are 1-based. If no match is found, it will return nothing, resulting in no replacement being done.
return to our expression to let it return result, calculate it by compiling as Lua function and calling it, perform rounding (this turned other way around to make it shorter).
It the end we get a numerical solution to our problem, only converting it back remains.
Making it crazy again
:gsub('%d',load'c=...+1 return l:sub(c,c)')
First line is a short way to convert number to string, so now we can call string methods in a short way. Let's do so!
gsub is called again to replace everything back to insanity. This time
%d is used instead of
. as replacement pattern as our function may and must process only numbers (
. would result to error on negative numbers). This time function (
loaded again to save bytes) first adds
1 to its first (and only) vaargument, converting it to position in dict string, then returns character from it at that position.
Hooray, almost there!
Dramatic finale, or Why Brackets Matter
Well… why two pairs of brackets anyways? It's time to talk about parall… eh, multiple return in Lua. Thing is that one function may return few values from one call (look at this meta question for more examples).
gsub returned two values: answer string we need and amount of replacements done (count of digits actually, but who cares). If it wasn't for internal pair, both string and number would be printed, screwing us up. So here we sacrifice two bytes to omit second result and finally print product of this insanity factory.
Well, I've enjoyed explaining almost as much as golfing in first place, hope you got what's going on here.