RegEx, exclude search in any brackets



  • You need to find all the commas and after them make a line break, And how to exclude the search between any brackets?
    This is to create a macro to format a compressed CSS file.

    У нас есть это:

    .layoutBlock_noborder_KYBnB5Up, .layoutBlock_39IwNSU_,.layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    

    That’s what we need to get:

    .layoutBlock_noborder_KYBnB5Up, 
    .layoutBlock_39IwNSU_,
    .layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    


  • Perhaps any of these expressions that use a negative lookahead so that the selected comma is not one eventually followed by any amount of characters except an opening bracket and finally a closing bracket could work?
    Find what: ,(?![^{]*}) or ,(?![^\(]*\))
    Replace: ,\r\n



  • @litos81
    It is absolutely true that not need to touch anything inside any parentheses.



  • @andrecool-68 said in RegEx, exclude search in any brackets:

    It is absolutely true that not need to touch anything inside any parentheses.

    So then you have your solution then, or do you need more help with this?



  • Hello, @andrecool-68, @litos81, @alan-kilborn and All,

    Glad to help you, this time ! I’m taking up the @litos81’s idea a little bit but, instead of using a negative look-ahead, I chose a positive one which ensures that all the commas searched are always followed with a complete multi-lines block {.......}.

    Two other tricks :

    • If a space char follows the comma, it is deleted when moving to next line.

    • A negative look-ahead (?!\R) prevent from extra-blank lines if, by mistake, you decide to run, again, this S/R on the replacement text itself !

    Thus, the regex S/R :

    SEARCH ,\x20?(?!\R)(?=[^{}]*\{[^{}]+\})

    REPLACE ,\r\n

    does change this text :

    .layoutBlock_noborder_KYBnB5Up, .layoutBlock_39IwNSU_,.layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    
    
    .layoutBlock_noborder_KYBnB5Up, .layoutBlock_39IwNSU_,.layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    

    as :

    .layoutBlock_noborder_KYBnB5Up,
    .layoutBlock_39IwNSU_,
    .layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    
    
    .layoutBlock_noborder_KYBnB5Up,
    .layoutBlock_39IwNSU_,
    .layoutBlock_noborder_KYBnB56Up{
        background-color:#fff;
        border-top:1px solid rgba(0,0,0,.12);
        border-right:1px solid rgba(0,0,0,.12);
        border-left:1px solid rgba(0,0,0,.12)
    }
    
    

    Best Regards,

    guy038



  • Hi all! @litos81 @guy038 @Alan-Kilborn

    The example of your regular expressions works, but if there is such a structure in the code, changes will be made (although everything is in general brackets):

    @-webkit-keyframes shake {
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    }
    

    This is an example of my macro that does the formatting of compressed CSS code.

    <Macro name="CSS sort" Ctrl="no" Alt="no" Shift="no" Key="0">
    	<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
    	<Action type="3" message="1601" wParam="0" lParam="0" sParam="/*" />
    	<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
    	<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n\n/*" />
    	<Action type="3" message="1702" wParam="0" lParam="1792" sParam="" />
    	<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
    	<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
    	<Action type="3" message="1601" wParam="0" lParam="0" sParam="*/" />
    	<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
    	<Action type="3" message="1602" wParam="0" lParam="0" sParam="*/\n\n" />
    	<Action type="3" message="1702" wParam="0" lParam="1792" sParam="" />
    	<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
    	<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
    	<Action type="3" message="1601" wParam="0" lParam="0" sParam="{" />
    	<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
    	<Action type="3" message="1602" wParam="0" lParam="0" sParam="{\n\t" />
    	<Action type="3" message="1702" wParam="0" lParam="1792" sParam="" />
    	<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
    	<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
    	<Action type="3" message="1601" wParam="0" lParam="0" sParam="}" />
    	<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
    	<Action type="3" message="1602" wParam="0" lParam="0" sParam="\n\t}\n\n" />
    	<Action type="3" message="1702" wParam="0" lParam="1792" sParam="" />
    	<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
    	<Action type="3" message="1700" wParam="0" lParam="0" sParam="" />
    	<Action type="3" message="1601" wParam="0" lParam="0" sParam=";" />
    	<Action type="3" message="1625" wParam="0" lParam="1" sParam="" />
    	<Action type="3" message="1602" wParam="0" lParam="0" sParam=";\n\t" />
    	<Action type="3" message="1702" wParam="0" lParam="1792" sParam="" />
    	<Action type="3" message="1701" wParam="0" lParam="1609" sParam="" />
    </Macro>
    


  • To my macro, I wanted to add an option for formatting headers that are separated by commas, roughly speaking, this will be the second macro.
    For notepad++ there is no Tidy-CSS plugin, and you have to invent a curve bicycle)).



  • This regex should only work if:

    The beginning of a line that does not contain a space or tab at the beginning, but this line always ends with a curly brace.



  • Hi, @andrecool-68, @litos81, @alan-kilborn and All,

    Ah… OK ! In this case, we’ll need to use recursive regexes in order to find out, first, the greatest well-balanced block of nested blocks as, for instance, the string {....{.......{..{......{...}.........}..}....}...}


    So, before dealing with the comma character, I would use this regex S/R, written in free-spacing mode, in order to surround the outer block with the two control characters STX and ETX :

    SEARCH (?x) \{ (?: [^{}]++ | (?R) )* \}

    REPLACE \x02$0\x03

    Note that (?R) ( or (?0) ) is a recursive call to the whole match itself ( $0 ) and that [^{}]++ is an atomic range of allowed characters in a single {.....} block

    So, given this example, below :

    @-webkit-keyframes ,shake, bla,blah, waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    }
    
    @-webkit-keyframes ,shake, bla,blah, waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    }
    

    we get :

    @-webkit-keyframes ,shake, bla,blah, waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    }
    
    @-webkit-keyframes ,shake, bla,blah, waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    }
    

    However, note that the STX and ETX control chars are not displayed on our forum, although really present in text !


    Secondly, if we assume that :

    • The \x02 control character plays the role of the opening curly brace { in the regex of my previous post

    • The \x03 control character plays the role of the ending curly brace } in the regex of my previous post

    We just get the right regex S/R, which, in addition, deletes the STX and ETX control chars as well :

    SEARCH (?x) (,) \x20? (?= [^\x02\x03]*? \x02 [^\x02\x03]+? \x03) | [\x02\x03]

    REPLACE ?1,\r\n

    And, @andrecool-68, you get your expected text :

    @-webkit-keyframes ,
    shake,
    bla,
    blah,
    waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    }
    
    @-webkit-keyframes ,
    shake,
    bla,
    blah,
    waooohh{
        0%,to {
            transform: translateZ(0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    
        10%,20%,30%,40%,50%,60%,70%,80%,90% {
            transform: translate3d(20px,0,0)
        }
    
        15%,25%,35%,45%,5%,55%,65%,75%,85%,95% {
            transform: translate3d(-20px,0,0)
        }
    }
    

    Cheers,

    guy038



  • Hi,
    I was also still intrigued by this ‘functionality’ and I came out with an expression that uses what the manual calls a “continuation Escape” \G which matches the end of the previous match.
    So, based exclusively on a CSS example I think it could work… but it may also miss very intricate CSS rules as I admit this expression doesn’t take much care of nested blocks as @guy038 solution does:
    Find what: ((?:^\S|\G)[^\{,]*,\x20?)(?=.*{)
    Replace: $1\r\n
    Basically it searchs for any line that starts by a non-white character and selects any portion of text between the start or the previous match and a comma (and possible space) all the way until a { character.



  • @guy038 Thank you for help!
    I combined my macro and your two regular expressions into one, now everything works correctly and beautifully! But if the file is large (e.g. 100mb) the macro works for about 30 seconds))).


Log in to reply