Is there a more elegant solution?
Substituting speed for elegance, there are many quick wins for this sort of thing. Precompile your regexen with qr//, so each iteration doesn't compile them anew. Break out of the loop after the first successful match, if appropriate (the List::MoreUtils any approach does this, I think). Optimize the regex list and its application: can you profitably combine them, add modifiers like \b or ^, etc? Keep track of regex hit counts and sort your regex list now and then to apply the most common matches first, if appropriate.
The biggest win typically comes from rethinking the problem, of course. Without really knowing what you're attempting, it looks as though you might be trying to do some comparatively simple token matches. Something like
while (<INPUT>) {
if (/\b keyword \s+ (\w+)/ and exists $keywords{ $1 }) {
# .. do something with the token in $1
}
}
might do the trick. We'd need to see specific examples to give more specific advice.
-Mike