Lua, 162 151 150 bytes
- -11 bytes thanks to my idea of using
load
instead of function(...) end
- -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.
Explanation
Introduction
l,p=...
Assign values from arguments to variables. Our dictionary is l
and expression is p
.
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
p:gsub('.',
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 find
. ...
is first (and only) argument here as we're in vaarg function (any load
ed 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.
Solving
math.ceil(load('return '..ABOVE)()-0.5)
Prepend 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
(ABOVE..'')
: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!
Now 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 (load
ed 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
print((ABOVE))
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).
Here, last 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.
q.ioiopewioyetqorw...
. If so, what kind of rounding should be applied? \$\endgroup\$1
for5/3
, not2
, due to integer division (not rounding). This doesn't invalidate the challenge, but you may have to allow different acceptable answers for the same test case (see my T-SQL answer below). \$\endgroup\$