Replace alias to form phrases
JavaScript (ES6) 58
Recursive function
f=(s,h,r=s.replace(/#(1?\d)/g,(_,x)=>h[x]))=>r==s?r:f(r,h)
Test
f=(s,h,r=s.replace(/#(1?\d)/g,(_,x)=>h[x]))=>r==s?r:f(r,h)
// Version without default parameters, same length but using a global
// f=(s,h)=>(r=s.replace(/#(1?\d)/g,(_,x)=>h[x]))==s?r:f(r,h)
console.log=x=>O.textContent+=x+'\n'
;[
['##1#23',['WEIRD','0 C','AS']],
["#0!",["We are #1","#2","#3","#4 !","graduating"]],
["##0#1#0#21#3#4",["a","m","z","n","g"]],
["##0#1#0#21#13#4",["a","m","z","","g","","","","","","","","","n"]],
["#1#7#6y#4#7#10s#7b#11#0#0#11r#7#0h#6#5#2#5#9#4.",
["t","#12#3","#11ga#3","#0#10v#11","#0h#10#8g","#7#8","a#8"," ","n","o","i","e","P#9s#10"]
],
["#0 & #3",["Programming #1","Puzzles","Code","#2 Golf"]]
].forEach(t=>{
var a=t[0],b=t[1]
console.log(a+' ['+b+']\n -> '+f(a,b))
})
<pre id=O></pre>
Julia, 112 107 66 bytes
f(s,x)=(r=replace(s,r"#1?\d",m->x[1+parse(m[2:end])]))==s?s:f(r,x)
This is a recursive function that accepts a string an an array and returns a string. It uses 0-based indexing.
We begin by constructing a string r as the input string s with all matches of the regular expression #1?\d
replaced with the element of x corresponding to 1 + the integer parsed out of the match. If this is equal to s, we return s, otherwise we recurse, passing r as the string.
Mathematica, 74 bytes
FixedPoint[#~StringReplace~a&,a=0;a=Reverse["#"<>ToString@a++->#&/@#2];#]&
Not too complicated. Most of it is just dedicated to creating the indices.