You can fetch all occurences of characters that are not within your character-class.
Negate the class [...] -> [^...] and then fetch all matches.
$firstname = 'Mr. (Awkward) Double-Barrelled';
if ( 0 < preg_match_all("/[^a-zA-Z .-]+/", $firstname, $cap) ) {
foreach( $cap[0] as $e ) {
echo 'invalid character(s): ', htmlspecialchars($e), "\n";
}
}
using the PREG_OFFSET_CAPTURE flag described at http://docs.php.net/preg_match_all you can even tell the user where that character is in the input.
edit: Or you can use preg_replace_callback() to visually mark the invalid characters somehow.
e.g (using an anonymous function/closure, php 5.3+)
$firstname = 'Mr. (Awkward) Double-Barrelled';
$invalid = array();
$result = preg_replace_callback("/[^a-zA-Z .-]+/", function($c) use(&$invalid) { $invalid[] = $c[0]; return '['.$c[0].']'; }, $firstname);
if ( $firstname!==$result ) {
echo 'invalid characters: "', join(', ', $invalid), '" in your input: ', $result;
}
prints invalid characters: "(, )" in your input: Mr. [(]Awkward[)] Double-Barrelled