Search code examples
cssregexeclipsegwt

Using a Regex to Replace Text Across Multiple Lines


I have some css files in a gwt project that need to be updated. I need to figure out a regex expression that I can use to locate and replace template expressions ('%sometext%') while also appending some prefix text based on the template before each block. For example lets say I have a chunk of css like the following:

.x-tabs-wrap, .x-layout-panel .x-tabs-top .x-tabs-wrap {
    background: #deecfd;
    border: 1px solid #8db2e3;
    padding-bottom: 2px;
    padding-top: 0;
}

.x-tabs-strip-wrap{
    padding-top: 1px;
    background: url('%aerotabStripBggif%') #cedff5 repeat-x bottom;
    border-bottom: 1px solid #8db2e3;
}

.x-tabs-strip .x-tabs-text {
    color: #15428b;
    font: bold 11px tahoma,arial,verdana,sans-serif;
}

.x-tabs-strip .on .x-tabs-text {
    cursor: default;
    color: #15428b;
}

.x-tabs-top .x-tabs-strip .on .x-tabs-right {
    background: url('%aerotabSpritegif%') no-repeat right 0;
}

The regex should match the second and fifth blocks and capture

  1. The whole block from the dot to the closing brace
  2. The opening template text url('%
  3. The template string aerotabSpritegif
  4. The closing template text %')

So the final expected result would be:

.x-tabs-wrap, .x-layout-panel .x-tabs-top .x-tabs-wrap {
    background: #deecfd;
    border: 1px solid #8db2e3;
    padding-bottom: 2px;
    padding-top: 0;
}

@url aerotabStripBggif aerotabStripBggif;
.x-tabs-strip-wrap{
    padding-top: 1px;
    background: aerotabStripBggif #cedff5 repeat-x bottom;
    border-bottom: 1px solid #8db2e3;
}

.x-tabs-strip .x-tabs-text {
    color: #15428b;
    font: bold 11px tahoma,arial,verdana,sans-serif;
}

.x-tabs-strip .on .x-tabs-text {
    cursor: default;
    color: #15428b;
}

@url aerotabSpritegif aerotabSpritegif;
.x-tabs-top .x-tabs-strip .on .x-tabs-right {
    background: aerotabSpritegif no-repeat right 0;
}

I have tried multiple different approaches and so far I can't find anything that matches correctly. Everything is either too narrow and matches nothing or too wide and ends up matching across multiple blocks. The best I have been able to come up with so far is:

(?s)^\.[A-Za-z]+?.+?url\(\'\%.+?\%\'\).+?\} 

Looking at the tools on regex101 I can see that no match for url is found in the first block of text, so the matcher keeps going until it eventually finds a match in the second block. I need to somehow define that the opening dot and the closing brace are boundaries but I can't seem to figure out how to do that.

What am I doing wrong here? What do I need to do to get this regex to behave as expected?


Solution

  • Would you please try the search pattern:

    (?m)^(\.[^}]+?)url\('%(.+?)%'\)([^}]+})
    

    and the replacement:

    @url $2 $2;\n$1$2$3
    

    Demo

    • The multiline mode (?m) makes the caret ^ match the start of any line.
    • As you have found, the regex .+?url tries to match across blocks even though you have put the ? to disable the greedy match. This is because the dot . matches anything regardless of the boundary. I have then modified it to [^}]+?url not to go far beyond the block.