Using any awk in any shell on every Unix box and using literal string operations so we don't care about any regexp or backreference metachars in the input or exceptions list:
$ cat tst.awk
NR==FNR {
map[$0]mask[$0] = RS NR RS
next
}
{
delete changed
for (exception in mapmask) {
while ( s=index($0,exception) ) {
$0 = substr($0,1,s-1) map[exception]mask[exception] substr($0,s+length(exception))
changed[exception]
}
}
gsub(/dank/,"monk")
for (exception in changed) {
while ( s=index($0,map[exception]mask[exception]) ) {
$0 = substr($0,1,s-1) exception substr($0,s+length(map[exception]mask[exception]))
}
}
print
}
$ awk -f tst.awk exceptions file
xdankine remonkus
dankzwd
monke monkbe
testmonk
The above assumes you don't have exceptions that are substrings of other exceptions like dankfoo and dankdankfoo since you don't show cases like that in the example in your question. If you do then make sure the exceptions file is sorted such that the longer superstrings come before the shorter substrings and iterate on them in the order they were input so you don't replace xdankdankfooy with xdank<replacement>y instead of x<replacement>y when masking the exceptions in the first loop.