Se vuoi fare tutto in una unica RE, la cosa si complica enormemente.
Conviene fare i singoli controlli con espressioni separate, e poi mettere insieme il risultato dei controlli.

Esempio:
codice:
~ /([^a-zA-Z0-9])/;
my $ok = $1.length;
~ /([a-z])/;
$ok *= $1.length;
~ /([A-Z])/;
$ok *= $1.length;
~ /(\d)/;
$ok *= $1.length;
if($ok) # tutte le condizioni verificate