First, it sounds like your strings are in the form of
<single><single>pretty much anything<single><single>.
So first of all, why not strip off the leading and trailing <single><single>, do your string munging, then put them back? Do you have embedded/escaped <single><single> to worry about, as well?
Second, are you doing this in perl? If so, you could probably make use of perl's extended regular expressions. Second, I'd say it's easier to do two passes, rather than trying to combine everything into one go.
My solution (using perl) would look like this:
$s =~ s/^''(.*)''$/$1/;
$s =~ s/[%&]//g;
$s =~ s/(?<!')'(?!')//g;
$s = qq(''$s'');
The (?<!') is a negative look behind for a single quote, and the (?!') is a negative look ahead for a single quote, so it matches single quotes that are not led by, nor followed by, a single quote. However, if the single quote is at the beginning of your string, following the two initial single quotes, then you're stuck (which is part of the reason I say strip the leading/trailing quotes off).
If you feed a string like so:
$s = q(''This is ' a string with it's single and double''quotes'');
$s =~ s/(?<!')'(?!')//g;
print qq($s\n);
You get the following output:
''This is a string with its single and double''quotes''
Perhaps we could give a better solution if you gave us some examples of strings you're trying to filter, and the result that they should look like.
Hope that helps.