Один из вариантов - оставить буквы, которые вы наверняка хотите использовать в верхнем регистре, в верхнем регистре и использовать только функцию ucwords в верхнем регистре в начале слов. Вы бы не использовали ucwords. Вы бы использовали:
$string = preg_replace('/(^|[^a-zA-Z])[a-z]/e', 'strtoupper("$0")', $string);
Это будет прописная буква любой буквы, которая не следует за буквой.
В противном случае, если у вас есть список слов, которые вы хотите в верхнем регистре, я бы сделал это перед использованием ucwords, потому что ucwords никогда не строчные буквы. Это будет выглядеть так:
$string = strtolower($string);
foreach($mywordlist as $word)
$string = str_replace(strtolower($word), strtoupper($word), $string);
$string = ucwords($string);
Примечание: прег_ресло, которое я использовал выше, - это то, что я использую вместо слов ucwords все время, потому что в верхнем регистре слова там, где есть непробельные символы. Пример: ucwords превращает тик-так в тик-так. Мой preg_replace превращает его в Tick-Tock.