You asked, whether to use /\[u\](.*?)\[u\]/g or /\[u\]\([^\[u\]]+)\[u\]/g. Both patterns are not designed with an ending-tag, which is important. [u]underlined text[/u] is BBCode
A solution using extended regex could be the use of recursive patterns. I think there is no support in JavaScript yet, but works fine e.g with PHP which uses PCRE.
The problem: Tags can be nested and this will make it difficult, to match the outermost ones.
Understand, what the following patterns do in this PHP example:
$str =
'The [u][u][u]young[/u] quick[/u] brown[/u] fox jumps over the [u]lazy dog[/u]';
1.) Matching any character in [u]...[/u] using the dot non-greedy
$pattern = '~\[u\](.*?)\[/u\]~';
$str = preg_replace($pattern, '<u>\1</u>', $str);
echo htmlspecialchars($str);
outputs:
The <u>[u][u]young</u> quick[/u] brown[/u] fox jumps over the <u>lazy dog</u>
Looks for the first occurence of [u] and eats up as few characters as possible to meet the conditional [/u] which results in tag-mismatches. So this is a bad choice.
2.) Using negation of square brackets [^[\]] for what is inside [u]...[/u]
$pattern = '~\[u\]([^[\]]*)\[/u\]~';
$str = preg_replace($pattern, '<u>\1</u>', $str);
echo htmlspecialchars($str);
outputs:
The [u][u]<u>young</u> quick[/u] brown[/u] fox jumps over the <u>lazy dog</u>
It looks for the first occurence of [u] followed by any amount of characters, that are not [ or ] to meet the conditional [/u]. It is "safer" as it only matches the innermost elements but still would require additonal effort to resolve this from inside out.
3.) Using recursion + negation of square brackets [^[\]] for what is inside [u]...[/u]
$pattern = '~\[u\]((?:[^[\]]+|(?R))*)\[/u\]~';
$str = preg_replace($pattern, '<u>\1</u>', $str);
echo htmlspecialchars($str);
outputs:
The <u>[u][u]young[/u] quick[/u] brown</u> fox jumps over the <u>lazy dog</u>
Similar to the the second pattern: Look for the first occurence of [u] but then EITHER match one or more characters, that are not [ or ] OR paste the whole pattern at (?R). Do the whole thing zero or more times until the conditional [/u] is matched.
To get rid of the remaining bb-tags inside, that were not resolved, we now can easily remove them:
$str = preg_replace('~\[/?u\]~',"",$str);
And got it as desired:
outputs:
The <u>young quick brown</u> fox jumps over the <u>lazy dog</u>
For sure there are different ways achieving it, like preg replace callback or for JavaScript the replace() method that can use a callback as replacement.