3
\$\begingroup\$

I have created a working function for cleaning some specific styles within the text from a WYSIWYG editor.

  var rulesText = textArea.value;

  var selector = "a:link, span.MsoHyperlink";
  var pattern = new RegExp(selector.replace(/\./g, "\\.") + "\\s*{[^}]*?}", "gim");

  rulesText = rulesText.replace(pattern,"");

  var nextSelector = "a:visited, span.MsoHyperlinkFollowed";
  var nextPattern = new RegExp(nextSelector.replace(/\./g, "\\.") + "\\s*{[^}]*?}", "gim");

  rulesText = rulesText.replace(nextPattern,"");

  textArea.value = rulesText;

  console.log("FIRED!");

Here are the styles being cleaned:

a:link, span.MsoHyperlink
{mso-style-unhide:no;
color:blue;
text-decoration:underline;
text-underline:single;}

a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
mso-style-priority:99;
color:purple;
mso-themecolor:followedhyperlink;
text-decoration:underline;
text-underline:single;}

This solution seems a bit wonky to me... And I feel like there is definitely more room for elegance. How can improve on this, possibly combine the two RegExp instances, and make sure that multiple instances of this are being removed?

\$\endgroup\$
  • \$\begingroup\$ Are selector and nextSelector dynamic? Are you reading them from somewhere or they are static and never going to change? \$\endgroup\$ – Tushar Mar 15 '17 at 14:37
  • \$\begingroup\$ @Tushar they are static, and most definitely will not change. \$\endgroup\$ – finesse.png Mar 15 '17 at 14:38
  • \$\begingroup\$ Can you please explain what do you mean by problematic styles or add some examples perhaps. Also, by , in selectors do you mean OR condition in RegEx? \$\endgroup\$ – Tushar Mar 15 '17 at 14:39
  • \$\begingroup\$ @Tushar I definitely left that out, and i am adding it now. Thank you. \$\endgroup\$ – finesse.png Mar 15 '17 at 14:41
  • \$\begingroup\$ @Tushar, as for the , it is simply part of the string. \$\endgroup\$ – finesse.png Mar 15 '17 at 14:47
3
\$\begingroup\$

As selectors are static(known beforehand) and are not going to change, there is no need to use RegExp constructor syntax to create regex. By saying that,

var selector = "a:link, span.MsoHyperlink";
var pattern = new RegExp(selector.replace(/\./g, "\\.") + "\\s*{[^}]*?}", "gim");

seems unnecessary. With these two statements, you're creating two extra variables, an additional replace and then creating a regular expression from string. Same is for other selector too.

What if there are 10 more CSS rules to be removed? Will you create 10 more strings, 10 more regex and 10 replacements? And what if there are 100 such rules?

The point is, this is not maintainable solution and the code written is way too much for string removals.

possibly combine the two RegExp instances, and make sure that multiple instances of this are being removed?

The two regex can be combined using OR condition in regex with g flag to replace all occurrences.

First, using regex literal syntax to create regex

var linksRegex = /a:link, span\.MsoHyperlink\s*{[^}]*?}/gim; // First selector regex

and

var visitedLinksRegex = /a:visited, span\.MsoHyperlinkFollowed\s*{[^}]*?}/gim; // Second selector regex

Using OR condition(|), the two regex can be combined as

/a:link, span\.MsoHyperlink\s*{[^}]*?}|a:visited, span\.MsoHyperlinkFollowed\s*{[^}]*?}/

This works. But, there is duplication of the part \s*{[^}]*?} which can be removed using groups

/(a:link, span\.MsoHyperlink|a:visited, span\.MsoHyperlinkFollowed)\s*{[^}]*?}/

I'll suggest to use \s* instead of space between two selectors which will match any number of any space characters(space, tab, vertical tabs, etc.)

/(a:link,\s*span\.MsoHyperlink|a:visited,\s*span\.MsoHyperlinkFollowed)\s*{[^}]*?}/

To match the CSS rule properties of a selector use [\s\S]*?} where [\s\S] will match any character(space characters and non-space characters) thus no need of m flag anymore, while *? following it will make the regex lazy. See http://www.regular-expressions.info/repeat.html. Lazy repetition will match fewer characters to satisfy the following condition in regex. So, [\s\S]*?} will match anything until } character.

Note: . does not match new-line character even with m-multiline flag Demo. Work-around is to use [\s\S] which matches any character. See Javascript regex multiline flag doesn't work

With these changes the regex will become

/(a:link,\s*span\.MsoHyperlink|a:visited,\s*span\.MsoHyperlinkFollowed)[\s\S]*?}/gi

Here's demo.


Final Code:

var regex = /(a:link,\s*span\.MsoHyperlink|a:visited,\s*span\.MsoHyperlinkFollowed)[\s\S]*?}/gi;

textArea.value = textArea.value.replace(regex, '');

Here's working demo in action to try it out.

function replaceRules() {
  var regex = /(a:link,\s*span\.MsoHyperlink|a:visited,\s*span\.MsoHyperlinkFollowed)[\s\S]*?}/gi;

  var textArea = document.querySelector('textarea');
  textArea.value = textArea.value.replace(regex, '');
}
input {
  margin-bottom: 5px;
  color: green;
  padding: 5px;
}

textarea {
  width: 100%;
}
<input type="button" value="Remove problematic rules" onclick="replaceRules()" />

<textarea cols="40" rows="14">
body {
    background: red;
}

a:link, span.MsoHyperlink {
  mso-style-unhide: no;
  color: blue;
  text-decoration: underline;
  text-underline: single;
}

a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
mso-style-priority:99;
color:purple;
mso-themecolor:followedhyperlink;
text-decoration:underline;
text-underline:single;}

a {
    color: gray;
}
</textarea>

\$\endgroup\$
  • \$\begingroup\$ Beautiful explanation! Thank you for not only providing a wonderful solution but for also explaining every part of it in depth. Much appreciated. \$\endgroup\$ – finesse.png Mar 15 '17 at 15:28
  • \$\begingroup\$ shorthand for \s\S: . \$\endgroup\$ – Vogel612 Mar 16 '17 at 10:58
  • \$\begingroup\$ @Vogel612 Sadly, . do not match new-line in JS. See this demo. Also, see this answer explaining same. \$\endgroup\$ – Tushar Mar 16 '17 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.