in reply to Regex grabs too much

First, I would recommend you look into Text::Template. Everything you are trying to do here has been done better than I could do it :)

Second, try:

$line=s/~\s*([^~]*?) ~/$$1/ge;
The /e should cause the right-hand side of the s// to be evaluated as a symbolic reference. the ? after the * makes it non-greedy, leaving a space.