Note that there are some explanatory texts on larger screens.

plurals
  1. PORegular Expression - Formatting text in a block - IM
    text
    copied!<p>Hello I am trying to figure out a regular expression to replace text in an innerHTML block to provide local formatting for text similar in operation to Google IM.</p> <pre><code>Where: _Italics_ !Inderline! *Bold* -Strike- </code></pre> <p>Part of the conditions is that the text must be wrapped by the symbol, but if a space follows immediately after then the trigger condition is voided; so * bold* would not be bolded and: * notbold<em>but this is bold</em></p> <p>The innerHTML will have URLS which have already been converted to hrefs so in order to not mess with them, I have added the following to the front of my regex. </p> <pre><code> (?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;) </code></pre> <p>The following javascript does not capture all the results and will have varied results depending on the order in which I conduct the replace.</p> <pre><code>var boldPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)\*([^\s]+[\s\S]?[^\s]+)\*([\s_!-]?)/gi; var italicsPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)_([^\s]+[\s\S]?[^\s]+)_([\s-!\*]?)/gi; var strikethroughPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)-([^\s]+[\s\S]?[^\s]+)-([\s_!\*]?)/gi; var underlinePattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)!([^\s]+[\s\S]?[^\s]+)!([\s-_\*]?)/gi; str = str.replace(strikethroughPattern, '&lt;span style="text-decoration:line-through;"&gt;$1&lt;/span&gt;$2'); str = str.replace(boldPattern, '&lt;span style="font-weight:bold;"&gt;$1&lt;/span&gt;$2'); str = str.replace(underlinePattern, '&lt;span style="text-decoration:underline;"&gt;$1&lt;/span&gt;$2'); str = str.replace(italicsPattern, '&lt;span style="font-style:italic;"&gt;$1&lt;/span&gt;$2'); </code></pre> <p>The test data for the 3 choose 4 looks like: </p> <pre><code>1 _-*ISB*-_ 2 _-!ISU!-_ 3 _*-IBS-*_ 4 _*!IBU!*_ 5 _!-IUS-!_ 6 _!*IUB*!_ 7 -_*SIB*_- 8 -_!SIU!_- 9 -*_SBI_*- 10 -*!SBU!*- 11 -!_SUI_!- 12 -!*SIB*!- 13 *_-BIS-_* 14 *_!BIU!_* 15 *-_BSI_-* 16 *-!BSU!-* 17 *!_BUI_!* 18 *!-BUS-!* 19 !_-UIS-_! 20 !_*UIB*_! 21 !-_USI_-! 22 !-*USB*-! 23 !*_UBI_*! 24 !*-UBS-*! </code></pre> <p>Can you even have a 4 level deep nested style span like any of the 24 permutations where all 4 modes are selected like: </p> <pre><code> -!_*SUIB*_!- </code></pre> <p>Thanks I've been fighting this for about a week.</p> <p>Bonus points for avoiding bad feedback from Mozilla for "Markup should not be passed to <code>innerHTML</code> dynamically." (I don't see how that might be possible when one is changing the formatting).</p> <p>Thanks a million regex wizards! I am in your debt.</p> <p>mwolfe.</p> <p><strong>Update</strong></p> <p>Using the same href detection as above and @talemyn help we are now at:</p> <pre><code>var boldPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)\*([^\s][^\*]*)\*/gi; var italicsPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)_([^\s][^_]*)_/gi; var strikethroughPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)-([^\s][^-]*)-/gi; var underlinePattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)!([^\s][^!]*)!/gi; str = str.replace(strikethroughPattern, '&lt;s&gt;$1&lt;/s&gt;'); str = str.replace(italicsPattern, '&lt;span style="font-style:italic;"&gt;$1&lt;/span&gt;'); str = str.replace(boldPattern, '&lt;strong&gt;$1&lt;/strong&gt;'); str = str.replace(underlinePattern, '&lt;u&gt;$1&lt;/u&gt;'); </code></pre> <p>Which seems to cover an extreme example:</p> <pre><code> _wow *a real* !nice *person! on -stackoverflow* figured- it out_ cool beans. </code></pre> <p>I think one could use the style spans and do a regex lookback to determine the previous unclosed span, close it, open a new span with old format plus new attribute, close when supposed and open a new span to finish the formatting .. but that could get messy or impossible to do with regular expressions as @NovaDenizen points out.</p> <p>Thank you for all your help. If there are any improvements please let me know. NB: I was unable to use and as the CSS on the site would not render it. Can that be overloaded? [This is for a firefox/greasemonkey/chrome plugin]</p> <p><strong>UPDATE (almost) FINAL</strong></p> <p>Using my 'broken' test phrase, as @MikeM correctly stated, as an example it would render correctly (minus the underline) in Google IM whether nested properly or not. So looking at the HTML output from the text in Google IM I noticed that it happily did not preformat the sting but simple did a substitute for as required. </p> <p>So after looking at the site code which was using resetcss to remove I needed to insert the CSS formatting via javascript. Stackoverflow to the rescue. <code>https://stackoverflow.com/questions/707565/how-do-you-add-css-with-javascript</code> and <code>https://stackoverflow.com/questions/20107/yui-reset-css-makes-strongemthis-not-work-em-strong</code></p> <p>So my solution now looks like:</p> <pre><code>.... var css = document.createElement("style"); css.type = "text/css"; css.innerHTML = "strong, b, strong *, b * { font-weight: bold !important; } \ em, i, em *, i * { font-style: italic !important; }"; document.body.appendChild(css); .... var boldPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)\*([^\s][^\*]*)\*/gi; var italicsPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)_([^\s][^_]*)_/gi; var strikethroughPattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)-([^\s][^-]*)-/gi; var underlinePattern = /(?!(?!.*?&lt;a)[^&lt;]*&lt;\/a&gt;)!([^\s][^!]*)!/gi; str = str.replace(strikethroughPattern, '&lt;s&gt;$1&lt;/s&gt;'); str = str.replace(italicsPattern, '&lt;i&gt;$1&lt;/i&gt;'); str = str.replace(boldPattern, '&lt;b&gt;$1&lt;/b&gt;'); str = str.replace(underlinePattern, '&lt;u&gt;$1&lt;/u&gt;'); ..... </code></pre> <p>And <code>tada</code> it mostly works!</p> <p><strong>UPDATE FINAL SOLUTION</strong> After a last minute simplification on the anchor element check from @MikeM and combining the conditions from another <a href="https://stackoverflow.com/questions/15288276/regex-query-help-lookbehind">stackoverflow</a> post we have arrived at a complete working solution. </p> <p>I also needed to add in a check for a one char style with closing symbol, since we were replacing trigger tokens side by side.</p> <p>As @acheong87 reminded be careful with \w as it includes the <code>_</code>, so that was added to the wrapping conditionals for all but the strikethroughPattern.</p> <pre><code>var boldPattern = /(?![^&lt;]*&lt;\/a&gt;)(^|&lt;.&gt;|[\s\W_])\*(\S.*?\S)\*($|&lt;\/.&gt;|[\s\W_])/g; var italicsPattern = /(?![^&lt;]*&lt;\/a&gt;)(^|&lt;.&gt;|[\s\W])_(\S.*?\S)_($|&lt;\/.&gt;|[\s\W])/g; var strikethroughPattern = /(?![^&lt;]*&lt;\/a&gt;)(^|&lt;.&gt;|[\s\W_])-(\S.*?\S)-($|&lt;\/.&gt;|[\s\W_])/gi; var underlinePattern = /(?![^&lt;]*&lt;\/a&gt;)(^|&lt;.&gt;|[\s\W_])!(\S.*?\S)!($|&lt;\/.&gt;|[\s\W_])/gi; str = str.replace(strikethroughPattern, '$1&lt;s&gt;$2&lt;/s&gt;$3'); str = str.replace(italicsPattern, '$1&lt;i&gt;$2&lt;/i&gt;$3'); str = str.replace(boldPattern, '$1&lt;b&gt;$2&lt;/b&gt;$3'); str = str.replace(underlinePattern, '$1&lt;u&gt;$2&lt;/u&gt;$3'); </code></pre> <p>Thank you so much everyone (@MikeM, @talemyn, @acheong87, et al.)</p> <p>mwolfe.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload