1

I am currently working with Kendo UI for jQuery Editor. The issue that I have is to convert all the "margin" attributes (margin, margin-left, margin-right and so) assigned to a block element (assigned by the Editor on using the indent control) to the adjacent padding attribute. Now I need to generate a regex using some javascript that can do the substring replacement for me but need to tackle many cases like not to replace margin that comes in as part of some text and so.

So far the regex that I came up is:

/<.*style.*margin.*>/g

The logic being to get the margin attributes that actually exists inside the style of some html tag.

The question here is that is this regex sufficient to deal with the case I want along with how to use this regex to only replace the "margin" keyword with "padding" inside this pattern.

Also in case of string like:

<a style="margin-left:12px">ABC</a> <p style="margin:10px>Some data</p>

It returns above as a single pattern rather then two different patterns, so how to handle this case as well?

0

3 Answers 3

2

Provided both the answers by @Simon and @Booboo failed to solve the problem for such string(s):

<a style='margin:12px; margin-left:13px'><p style='margin-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='margin:123;margin-right:12px'><margin></p>

I had to answer the question myself.

So what I did was build up the following regex:

/<[a-z]+[^>]*style\s*=\s*['"][^'">]*margin[^>]*/gi
  1. First look for start of an HTML tag (<)
  2. Next at least one alphabet is required indicating the HTML tag ([a-z]+)
  3. Next any number of characters is accepted, except for a >, till a 'style' is found ([^>]*style)
  4. Next any number of space between the style and '=' (\s*=)
  5. Also any number of space between the right of equal and a quote, ' or ", (\s*['"])
  6. Next accept any number of characters, except ', " or > , till the margin is found ([^'">]*margin)
  7. Next accept any number of characters, except > ([^>]*)

The gi and flags representing to search globally and case insensitivity.

Also the code example to replace the margin attributes with margin is as follows:

var regex = /<[a-z]+[^>]*style\s*=\s*['"][^'">]*margin[^'">]*/gi;

var str = "<a style='margin:12px; margin-left:13px'><p style='margin-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='margin:123;margin-right:12px'><margin></p>";
var new_s = str.replace(regex,
    function(match) {
        return match.replace(/margin/gi, 'padding');
    }
);
console.log(new_s);

And the output:

<a style='padding:12px; padding-left:13px'><p style='padding-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='padding:123;padding-right:12px'><margin></p>

Also you can see the Regex details here.

And how the provided other answers behave wrong:

On the other hand the output of regex by @Simon:

Regex:

/<\s*[a-z]+.*?style\s*=\s*"(?<margin>margin).*?".*?\/?>/gsi

Output:

<a style='margin:12px; margin-left:13px'><p style='margin-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='margin:123;margin-right:12px'><margin></p>

And also @Booboo regex and output:

Regex:

/[a-z]+\s+(?:(?!>).*?)\bstyle\s*=\s*(['"])(?:(?!\1).*?)(margin)/gmis

Output:

<a style='padding:12px; margin-left:13px'><p style='padding-top:13px'></p>Margin</a> Hello margin top <p padding:13><p style='padding:123;margin-right:12px'><margin></p>

EDIT 18-Dec-2019 ------------------------------------------------------------------------------

Thanks to @Booboo for pointing out that the regex still might have problems copping with string like:

<img src='../marginally-wrong-documents/a.jpg' style='display: block; margin: 20px;'>

Thus, for above string my regex:

/<[a-z]+[^>]*style\s*=\s*['"][^'">]*margin[^'">]*/gi

and @Booboo's updated regex:

(<[a-z]+\s+(?:(?!>).*?)\bstyle\s*=\s*)(['"])((?:(?!\2)).*?margin(?:(?!\2).)*)(\2)

Will fail.

So to cope with this I have worked out the following changes in the code (keeping the regex same):

var regex = /<[a-z]+[^>]*style\s*=\s*['"][^'">]*margin[^'">]*/gi;

var str = "<img src='../marginally-wrong-documents/a.jpg' style='display: block; margin: 20px;'><a style='margin:12px; margin-left:13px'><p style='margin-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='margin:123;margin-right:12px'><margin></p>";

var new_s = str.replace(regex,
    function(match) {
       var regex2 = /margin[ -:]+/gi;
       match = match.replace(regex2, function(match2){
             return match2.replace(/margin/gi, "padding");
       });

       return match;
    }

);
console.log(new_s);

So what's new with this change:

  1. Now get the pattern containing the margin pattern as doing before.
  2. Now for every pattern find out a pattern that contains margin that is the actual regex's logic.
  3. For every sub pattern again run the new regex to separate out only the margin that is actually representing the CSS margin (-left, -right, -top, -bottom) attribute and replace it with padding.

Also the output for the above code using the new logic:

<img src='../marginally-wrong-documents/a.jpg' style='display: block; padding: 20px;'><a style='padding:12px; padding-left:13px'><p style='padding-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='padding:123;padding-right:12px'><margin></p>
Sign up to request clarification or add additional context in comments.

2 Comments

How would you handle <img src="../marginally-wrong-documents/a.jpg" style="display: block; margin: 20px;">? See my updated answer.
You have already commented on my original post and on the post of @Simon that it was not producing the correct results, which was a perfectly reasonable and correct thing to do. I am not sure why it was necessary to explicitly show other people's errors in your own answer after already having said it was necessary to answer you own question and having made corrective comments elsewhere.
1
/<\s*[a-z]+.*?style\s*=\s*"(?<margin>margin).*?".*?\/?>/gsi

Here is your answer

var re = /<\s*[a-z]+.*?style\s*=\s*"(?<margin>margin).*?".*?\/?>/gsi;

var testStr = `
<html>
  <body>
    <DIV style="margin-left:12px">
        <a href="" style="margin-left:12px" >Non-closed tag
        <a style="margin-left:12px" property="">汉字Unicode</a> 
        <a property="" style="margin-left:12px" > margin-left:12px</a> 
        <a style="margin-left:12px">new line
        </a> 
        <DIV style="margin:10px" /> 
        <b style="margin-left:12px"><i style="margin-left:12px"> nested in single line </i></b>

    </div>
  </body>
</html>
`;

var replaced = testStr.replace(re, replacer);

function replacer(match, p1, p2, offset, string) {
  return match.replace(p1, "padding");
}

alert(replaced);

Nothing magic in this regexp, I think it can match most of your needs.

1 Comment

Your regex doesn't works as expected. See the answer posted by me for details.
0

The regex I use is:

(<[a-z]+\s+(?:(?!>).*?)\bstyle\s*=\s*)(['"])((?:(?!\2)).*?margin(?:(?!\2).)*)(\2)
  1. (<[a-z]+\s+(?:(?!>).*?)\bstyle\s*=\s*) Catches in capture group 1 the start of a tag and everything through style= up to and but not including the opening single or double quote,
  2. (['"]) Catches in capture group 2 the opening single or double quote for the style specification.
  3. ((?:(?!\2)).*?margin(?:(?!\2).)*) Captures in capture group 3 the complete style specification that includes a margin keyword.
  4. (\2) Captures in capture group 4 a matching closing single or double quote to complete the style specification.

Together capture groups 1, 2, 3 and 4 comprise the complete match (group 0) but only group 3 comprises the more limited text that comprises the text that is the style string. So only the text of group 3 should be replaced to minimize the chance of modifying something that should not be modified. For example, you would not want to modify the URL in <img src="../marginally-wrong-documents/a.jpg" style="display: block; margin: 20px;">.

See Regex Demo

let s = `<div style='margin: 0'
    <p id="a" style="display:block; margin-right: 10px;">
        The margin should be at 10
    </p>
    <a style='margin:12px; margin-left:13px'><p style='margin-top:13px'></p>Margin</a> Hello margin top <p margin:13><p style='margin:123;margin-right:12px'><margin></p
</div>`;

let regex = /(<[a-z]+\s+(?:(?!>).*?)\bstyle\s*=\s*)(['"])((?:(?!\2)).*?margin(?:(?!\2).)*)(\2)/gmis;
let new_s = s.replace(regex,
    function(match, p1, p2, p3, p4) {
        return p1 + p2 + p3.replace(/margin/gi, 'padding') + p4
    }
);
console.log(new_s);

3 Comments

Your regex doesn't works as expected. See the answer posted by me for details.
Thanks. I have updated not only the regex but also the explanation. Please read.
thanks for pointing out, I have updated the logic for which my previous and your current regex both failed. Have a look at the updated answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.