Generating minimal regular expression character classes
No answers after a few days, so thought I'd have a go. Found it trickier than expected, so the answer's pretty long, but I'm reasonably confident it works. Should be able to trim it a fair bit more.
Python 3.8, 431 405 410 bytes

import re,itertools as I
B,M,C,P=&quot;\-]^&quot;
s=sorted;x=s({*input()})
d=[ord(x)-i for i,x in enumerate(x)];l=[];i=0
for _,g in I.groupby(d):n=len([*g]);l+=[[x[i]+M+x[i+n-1]],x[i:i+n]][n&lt;4];i+=n
o=&quot;&quot;.join(s(l,key=lambda i:2*(M in i[::2])+(P in i)-3*(i[0]==M&lt;C not in x)-2*(C in i)))
print(&quot;[&quot;+re.sub(&quot;.&quot;,lambda m:B*((x:=m.group())==B or x==P==o[0]or x==M&lt;M*2==o[(i:=m.start()):i+2]in o[1:-1]or x==C in o[1:])+x,o)+C)

Try it online!
Explanation
The overall approach is to:

Split the letters into ranges of length at least 4 and individual characters. Note that ranges of length 3 are never necessary (eg. &quot;[abc]&quot; is the same length as &quot;[a-c]&quot; and &quot;[]\\[]&quot; is the same length &quot;[[-\]]&quot;) and are sometimes worse (e.g. &quot;]-./&quot; is shorter as  &quot;[]./-]&quot; than as &quot;[]\--/]&quot; or &quot;[--/\]]&quot;).

Sort the letters and ranges, so &quot;]&quot; goes first, otherwise &quot;-&quot; goes first, otherwise &quot;-&quot; goes last, and with &quot;^&quot; as late as posssible. There is no conflict between putting &quot;]&quot; first and &quot;-&quot; last since &quot;]--&quot; is not a valid range.

Escape as necessary: \ always, ] unless it's first, ^ if it's first, and - if it's in the middle (which will only happen if it's the beginning of a range).


Extra test cases
&quot;-^&quot;      =&gt; &quot;[-^]&quot;
&quot;-4]&quot;     =&gt; &quot;[]4-]&quot;
&quot;abcde^&quot;  =&gt; &quot;[a-e^]&quot;
&quot;XYZ[\\]&quot; =&gt; &quot;[X-\]]&quot;
&quot;-./0]&quot;   =&gt; &quot;[]\--0]&quot;
&quot;+*,-^&quot;   =&gt; &quot;[\^*--]&quot;
&quot;^_`a&quot;    =&gt; &quot;[\^-a]&quot;