Generally you should avoid using
$',
$& and
$'. Once they appear in your program they slow down all regular expression calls. You can achieve the same functionality by specifying your own captures, i.e.
$input->{$key} =~ /[\<\>\:\"\|\?\*]/;
die "Error, found $&";
may be re-written as:
$input->{$key} =~ /([\<\>\:\"\|\?\*])/;
die "Error, found $1";
Am I doing it right? The ^a-zA-Z?:? is at the beginning as paths my be full windows paths. Although I get the feeling I problem mean ^(a-zA-Z:)?
I think you'll want
^([a-zA-Z]:)?. It depends on if
:\some\path is a valid path (i.e. a leading colon without a drive letter.)
The final method you've come up with is about the best you can do. For each error message that you can emit you have to develop a test for it. The only problem I see is that another way your validation test can fail is if there are no valid characters after the "drive:" prefix, e.g. "C:". In that case you'll want a different error message.
Honestly, I don't see what's wrong with just saying:
die "Invalid path: $input->{$key}\n";
By including the offending path in the output it should be easy for the user to tell what the problem is.