<p>I am trying to write some JavaScript RegEx to replace user inputed tags with real html tags, so <code>[b]</code> will become <code>&lt;b&gt;</code> and so forth. the RegEx I am using looks like so</p>

<pre><code>var exptags = /\[(b|u|i|s|center|code){1}]((.){1,}?)\[\/(\1){1}]/ig;
</code></pre>

<p>with the following JavaScript</p>

<pre><code>s.replace(exptags,"&lt;$1&gt;$2&lt;/$1&gt;");
</code></pre>

<p>this works fine for single nested tags, for example:</p>

<pre><code>[b]hello[/b] [u]world[/u]
</code></pre>

<p>but if the tags are nested inside each other it will only match the outer tags, for example </p>

<pre><code>[b]foo [u]to the[/u] bar[/b]
</code></pre>

<p>this will only match the <code>b</code> tags. how can I fix this? should i just loop until the starting string is the same as the outcome? I have a feeling that the <code>((.){1,}?)</code> patten is wrong also?</p>

<p>Thanks</p>

[{'answer_id': 81074, 'author': 'Eugen Anghel', 'author_id': 4017, 'author_profile': 'https://Stackoverflow.com/users/4017', 'pm_score': 1, 'selected': False, 'text': '<p>AFAIK you can\'t express recursion with regular expressions. </p>\n\n<p>You can however do that with .NET\'s System.Text.RegularExpressions using balanced matching. See more here: <a href="http://blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx" rel="nofollow noreferrer">http://blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx</a> </p>\n\n<p>If you\'re using .NET you can probably implement what you need with a callback. \nIf not, you may have to roll your own little javascript parser.</p>\n\n<p>Then again, if you can afford to hit the server you can use the full parser. :)</p>\n\n<p>What do you need this for, anyway? If it is for anything other than a preview I highly recommend doing the processing server-side.</p>\n'}, {'answer_id': 81123, 'author': 'vava', 'author_id': 6258, 'author_profile': 'https://Stackoverflow.com/users/6258', 'pm_score': 0, 'selected': False, 'text': '<p>Yes, you will have to loop. Alternatively since your tags looks so much like HTML ones you could replace <code>[b]</code> for <code>&lt;b&gt;</code> and <code>[/b]</code> for <code>&lt;/b&gt;</code> separately. (.){1,}? is the same as (.*?) - that is, any symbols, least possible sequence length.</p>\n\n<p>Updated: Thanks to MrP, (.){1,}? is (.)+?, my bad.</p>\n'}, {'answer_id': 81142, 'author': 'Richard Szalay', 'author_id': 3603, 'author_profile': 'https://Stackoverflow.com/users/3603', 'pm_score': 0, 'selected': False, 'text': "<p>You are right about the inner pattern being troublesome.</p>\n\n<pre><code>((.){1,}?)\n</code></pre>\n\n<p>That is doing a captured match at least once and then the whole thing is captured. Every character inside your tag will be captured as a group.</p>\n\n<p>You are also capturing your closing element name when you don't need it and are using <code>{1}</code> when that is implied. Below is a cleanup up version:</p>\n\n<pre><code>/\\[(b|u|i|s|center|code)](.+?)\\[\\/\\1]/ig\n</code></pre>\n\n<p>Not sure about the other problem.</p>\n"}, {'answer_id': 81393, 'author': 'Marijn', 'author_id': 12038, 'author_profile': 'https://Stackoverflow.com/users/12038', 'pm_score': 0, 'selected': False, 'text': '<p>You could just repeatedly apply the regexp until it no longer matches. That would do odd things like "[b][b]foo[/b][/b]" => "&lt;b>[b]foo&lt;/b>[/b]" => "&lt;b>&lt;b>foo&lt;/b>&lt;/b>", but as far as I can see the end result will still be a sensible string with matching (though not necessarily properly nested) tags.</p>\n\n<p>Or if you want to do it \'right\', just write a simple recursive descent parser. Though people might expect "[b]foo[u]bar[/b]baz[/u]" to work, which is tricky to recognise with a parser.</p>\n'}, {'answer_id': 81418, 'author': 'Jonathan Lonowski', 'author_id': 15031, 'author_profile': 'https://Stackoverflow.com/users/15031', 'pm_score': 0, 'selected': False, 'text': '<p>The reason the nested block doesn\'t get replaced is because the match, for [b], places the position after [/b]. Thus, everything that ((.){1,}?) matches is then ignored.</p>\n\n<p>It is possible to write a recursive parser in server-side -- Perl uses <a href="http://perldoc.perl.org/functions/qr.html" rel="nofollow noreferrer">qr//</a> and Ruby probably has something similar.</p>\n\n<p>Though, you don\'t necessarily need true recursive. You can use a relatively simple loop to handle the string equivalently:</p>\n\n<pre><code>var s = \'[b]hello[/b] [u]world[/u] [b]foo [u]to the[/u] bar[/b]\';\nvar exptags = /\\[(b|u|i|s|center|code){1}]((.){1,}?)\\[\\/(\\1){1}]/ig;\n\nwhile (s.match(exptags)) {\n   s = s.replace(exptags, "&lt;$1&gt;$2&lt;/$1&gt;");\n}\n\ndocument.writeln(\'&lt;div&gt;\' + s + \'&lt;/div&gt;\'); // after\n</code></pre>\n\n<p>In this case, it\'ll make 2 passes:</p>\n\n<pre><code>0: [b]hello[/b] [u]world[/u] [b]foo [u]to the[/u] bar[/b]\n1: &lt;b&gt;hello&lt;/b&gt; &lt;u&gt;world&lt;/u&gt; &lt;b&gt;foo [u]to the[/u] bar&lt;/b&gt;\n2: &lt;b&gt;hello&lt;/b&gt; &lt;u&gt;world&lt;/u&gt; &lt;b&gt;foo &lt;u&gt;to the&lt;/u&gt; bar&lt;/b&gt;\n</code></pre>\n\n<hr>\n\n<p>Also, a few suggestions for cleaning up the RegEx:</p>\n\n<pre><code>var exptags = /\\[(b|u|i|s|center|code)\\](.+?)\\[\\/(\\1)\\]/ig;\n</code></pre>\n\n<ul>\n<li>{1} is assumed when no other count specifiers exist</li>\n<li>{1,} can be shortened to +</li>\n</ul>\n'}, {'answer_id': 81573, 'author': 'Joe Hildebrand', 'author_id': 8388, 'author_profile': 'https://Stackoverflow.com/users/8388', 'pm_score': 0, 'selected': False, 'text': "<p>Agree with Richard Szalay, but his regex didn't get quoted right:</p>\n\n<pre><code>var exptags = /\\[(b|u|i|s|center|code)](.*)\\[\\/\\1]/ig;\n</code></pre>\n\n<p>is cleaner.  Note that I also change <code>.+?</code> to <code>.*</code>.  There are two problems with <code>.+?</code>:</p>\n\n<ol>\n<li>you won't match [u][/u], since there isn't at least one character between them (+)</li>\n<li>a non-greedy match won't deal as nicely with the same tag nested inside itself (?)</li>\n</ol>\n"}, {'answer_id': 82990, 'author': 'freespace', 'author_id': 8297, 'author_profile': 'https://Stackoverflow.com/users/8297', 'pm_score': 0, 'selected': False, 'text': '<p>How about:</p>\n\n<pre><code>tagreg=/\\[(.?)?(b|u|i|s|center|code)\\]/gi;\n"[b][i]helloworld[/i][/b]".replace(tagreg, "&lt;$1$2&gt;");\n"[b]helloworld[/b]".replace(tagreg, "&lt;$1$2&gt;");\n</code></pre>\n\n<p>For me the above produces:</p>\n\n<pre><code>&lt;b&gt;&lt;i&gt;helloworld&lt;/i&gt;&lt;/b&gt;\n&lt;b&gt;helloworld&lt;/b&gt;\n</code></pre>\n\n<p>This appears to do what you want, and has the advantage of needing only a single pass.</p>\n\n<p>Disclaimer: I don\'t code often in JS, so if I made any mistakes please feel free to point them out :-)</p>\n'}, {'answer_id': 83441, 'author': 'A Nony Mouse', 'author_id': 7182, 'author_profile': 'https://Stackoverflow.com/users/7182', 'pm_score': 2, 'selected': False, 'text': '<p>The easiest solution would be to to replace all the tags, whether they are closed or not and let <code>.innerHTML</code> work out if they are matched or not it will much more resilient that way..</p>\n\n<pre><code>var tagreg = /\\[(\\/?)(b|u|i|s|center|code)]/ig\ndiv.innerHTML="[b][i]helloworld[/b]".replace(tagreg, "&lt;$1$2&gt;") //no closing i\n//div.inerHTML=="&lt;b&gt;&lt;i&gt;helloworld&lt;/i&gt;&lt;/b&gt;"\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/80963', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2098/']