In general, if you don't have a great need for it, do #1. It looks like an easy problem to solve but it can become mind-bendingly difficult. Much like blacklisting things, it's just an exercise in futility trying to tweak so that you catch every single one … and then, trying to make it quick.
With that said, if you really must do #2, then don't fall into the trap of thinking you can get it perfect and fast. You can't. It's a coding rabbit hole.
I created a registration / authentication server from B4J that most of my projects use now. It serves many clients' (and all of their users) apps as well as my own. One configuration setting for each client app is to do exactly #2. Having done this sort of thing many years ago, I thought I'd see where I and technology advances could finally make this work ideally. I'll have to wait a bit more, I suppose for A.I., quantum computers, and inspiration from the coding vespers before trying again.
The route I took on this latest B4J server (and it does work very well, mind you, but it isn't positively perfect AND fast), was to put the 'bad words' into records of an SQL table and read those into memory (a B4x list). Why memory instead of doing a SQL search? Because at last count there's only 167 words/records. Obviously, if you have a huge number of words, you'd want to rethink that. Although, you'll quickly run into speed problems (because that's a path I went down, too).
So, you've now got a list of 'bad words'. I compare each item in that list with the user name in a regular expression regex. You're right that you'll need to handle embedded 'bad words' and whether or not to reject just because a username may be "Muscuntly" or "TailsHit" or "Mash it" (the AOL Scunthorpe problem). Remember punctuation, too. For a small list, it's pretty fast. It quickly goes downhill at a certain point (ie supporting multiple languages … I have a configuration option for that, too, in order to limit that in-memory list). We've found that a more complex regex is fastest as compared to running multiple regex's. But, there's a limit to that, too, as it can become cumbersome and unwieldy.
Then, you have the human factor … Once you start filtering like that, your users will expect it to be perfect AND flexible. You'll never please them. You could spend more time tweaking (we did!!!) it than you want and it still won't be perfect.
The overarching suggestion from me is this: Do it if you must, but don't be surprised if you wished you never went there in the first place.