Breaking up CSS into blocks with regex - css

I have a stylesheet:
a,b,c { stuff
lots of it
}
b { more stuff }
.test { even more }
I want a regular expression to break it up into each of the three parts, separating from '}' to '}' should work alright for my needs (except the first case obviously).

In Ruby 1.9, you could
result = subject.split(/(?<=\})/)
i.e., split the string at a position following a }. Ruby 1.8 doesn't support lookbehind assertions, though, so it won't work there. And of course you'll be running into problems with nested braces, but you said that this shouldn't be a problem with your data.
In Ruby 1.8 (can't try it here), the following should work:
result = subject.split(/(\})/)
although now the closing braces won't be part of the matched elements anymore. So test {a} test2 {b} will be split into test {a, }, test2 {b, } plus an empty string.

It may be inappropriate in your case, but you could use a CSS parser to split your CSS file by tokens and operate on them independently and harmlessly.
css_parser (with this guide);
CSSPool (I recommend this one just because you only need to obtain certain selectors from your CSS; this one is like a SAX parser for CSS).

.scan(/.+?\}/m)

Related

regex to find pattern not inside another pattern

I'm trying to write a regex to find all ID selectors in a CSS file. Basically, that means any word that starts with a #, so okay
#\w+
Except ... color specifiers can also start with a #. So what I really want is all words that start with a # that are NOT between { and }. I can't figure out how to say this.
I'm doing this in Notepad++ so I need that flavor of regex.
BTW my real objective is to delete everything that's not an ID selector from the file, so I end up with just a list of selectors. My first try was
Find: [^#]*(#\w+)
Replace: \1\r\n
... and then hit Replace All.
But then I ran into the color problem.
Update
Someone asks for an example. Ok:
Input:
.foo {max-width: 500px;}
#bar {text-align: left;}
.splunge, #plugh {color: #ff0088;}
Desired output:
#bar
#plugh
Note the point is that it includes the two "pound strings" that come outside of braces but not the one that comes inside braces.
What about this? You could use a lookahead expression:
#\w+(?=[^}]*?{)
It ensures that a { follows the match (indicating that the match is part of a selector), but not after a } character (excluding any matches against color declarations in the CSS).
#: match must begin with a #
\w+: match one or more word characters (might need tweaked. \w is equivalent to [A-Za-z0-9_])
(?=...): positive lookahead
[^}]*?: Any character not matching }
{: the { character
https://regex101.com/r/Di43hX/3

Using special char in css class name works sometimes, except for one case

I'm passing in the page's filename with php into a selector in order to load a corresponding background-img for some page's header sections from the CSS. Due to the setup of my CMS, I'm forced to include the trailing slashes as well. So instead of a nice clean < header class="bg-pagename" >, it comes through as < header class="bg-/pagename/" > which is making things hairy in my CSS.
In my CSS file, I'm going by the solution here wyqydsyq Jun 5 '12 (\2f becomes /) which has worked for 5 page names so far, until I hit this one. Not sure why.. is there a regex or special character that's making this not work?
DOESNT WORK IN CSS FILE:
header.bg-\2fcomp-tour\2f {}
WORKED:
header.bg-\2fhol-tour\2f {}
header.bg-\2flaw-tour\2f {}
header.bg-\2fhigh-tour\2f {}
header.bg-\2fglam-tour\2f {}
(And yes I did think to "clean" the initial php function and remove the forward slashes before echoing the page name, but that just wasn't working for some reason :/ )
In \2fcomp, the letter C is a hexadecimal digit. So the parser is treating the escape sequence as \2fc, not \2f. As you can imagine, \2fc represents a completely different character to \2f. As a result, the selector fails to match.
G, H and L are not hexadecimal digits, so their corresponding selectors work as expected.
You work around this by space-padding the escape sequence like so:
header.bg-\2f comp-tour\2f
You can also just write \/ to represent a forward slash, instead of \2f, then you don't have to worry about hex digit collisions — it does look a little funny, though:
header.bg-\/comp-tour\/
header.bg-\/hol-tour\/
header.bg-\/law-tour\/
header.bg-\/high-tour\/
header.bg-\/glam-tour\/

regex replace to match url() paths in css and replace with asset_path

I've been trying to follow this SO answer to try and write some regex to do a pattern replace with Grunt. My regex understanding is very basic so I'm pretty lost.
Matching
.selector {
background: url('../img/some.filename.png') no-repeat;
}
Output
.selector {
background: url(<%= asset_path 'some.filename.png' %>) no-repeat;
}
I understand something like /url\(.*?g'\)/ig will match the url() tag but I'm not sure how to isolate the filename from within that. Using the Grunt string-replace task to run the replace.
Any pointers?
I have conjured a beast of a regex that I believe does the job. It requires a positive lookbehind and a positive lookahead which I don't know if Grunt supports since I don't know what that is. I'm going to assume it does, otherwise I don't think it's possible without the lookaround.
I tested this regex using C#, so here it is!
Regex:
(?<=url\s*\('([\w\._-]+/)*)([\w\._-]+)(?='\))
Test String:
url ('fruit-veggie/apple_orange-pie/this.is-my_file.png')
I will break this down as it befuzzles even me. This is composed of 3 major parts.
Positive lookbehind:
(?<=url\s*\('([\w\._-]+/)*)
The (?<=) indicates whatever comes between the = and ) has to be part of the pattern that follows, but it will not be part of the match.
url\s*\(' will match url (' with or without spaces.
([\w\._-]+/)* will match any string that contains at least one word character, dot, underscore, or dash, followed by a forward slash. This will consume one folder path. The * at the end will make it consume any number of folders because you might not have a folder to begin with.
Actual file name:
([\w\._-]+)
This is identical to the folder pattern except without the forward slash at the end. This will match files without extensions.
Positive lookahead:
(?='\))
(?=) is the same as the positive lookbehind, except this is a lookahead which will check what comes after the pattern that precedes it.
'\) simply checks that the entire string is followed by a quote and a closing bracket.
For the folder/file name pattern, you will have to tweak it based on what characters would be valid in them. So if for whatever crazy reason they can contain a #, you will have to modify those portions of the regex to include that character.
Hopefully Grunt supports this regex, otherwise I will have wasted my time. But this was a fun challenge regardless!
Update
It seems JavaScript doesn't support lookbehinds. If what you're doing is specific to your current project only, why don't you try using two regex instead of one?
function GetFile (s) {
s = s.replace (/url\s*\('([\w\._-]+\/)*/g, '');
return s.match (/[\w\._-]+(?='\))/)[0];
}
var s = "url ('fruit-veggie/apple_orange-pie/this.is-my_file.png')";
console.log (GetFile (s));
This will erase everything up to but not including the first character of the file name. Then it returns the file name without the end quote and bracket, because JavaScript supports lookaheads.
You can use something like this :
(?:url\((.*?)\))
Demo
Explanation :
In javascript you can give :
var s="url('../img/some.filename.png')";
var ss= /(?:url\((.*?)\))/ ;
console.log(s.match(ss)[0]);

Capybara/Poltergeist: CSS ID with a colon raises Capybara::Poltergeist::InvalidSelector

I have a CSS selector with a colon in the name, which apparently is a problem.
Example:
selector = 'input#billing:street1'
find(selector)
I get the following error message:
The browser raised a syntax error while trying to evaluate the selector "input#billing:region_id" (Capybara::Poltergeist::InvalidSelector)
Is there any way to use the selector the way it is? I know that I could do something like that:
selector = 'billing:street1'
find(:xpath, ".//input[#id='#{selector}']")
but I'd prefer not to do it for various reasons.
I use Cucumber, Capybara, Poltergeist/PhantomJS
This is more of an educated guess based on my experience with CSS and Javascript, but you could try something like this:
selector = 'input#billing\:street1'
find(selector)
Notice the backslash in front of the colon, this escapes the character in CSS. For Javascript however, it is slightly different. You will need two slashes to escape the character. Like so:
selector = 'input#billing\\:street1'
find(selector)
I'm not sure which one would do the trick (if either would) since I have zero experience with Cucumber, Capybara, and Poltergeist/PhantomJS, but based on your code it looks as if you would want to try the double slash \\ option first.

How do I match individual CSS attributes using RegEx

I'm trying to expand a minified CSS file (don't ask) to make it human readable.
I've managed to get most of the expanding done but I'm stuck at a very weird case that I can't figure out.
I have CSS that looks like this:
.innerRight {
border:0;color:#000;width:auto;padding-top:0;margin:0;
}
a {
color:#000;text-decoration:underline;font-size:12px;
}
p,small,ul,li {
color:#000;font-size:12px;padding:0;
}
I've tried (.+):(.+); as the search and \t\1: \2;\n as the replace. The find RegEx is valid, the only problem is that it matches the entire line of attributes. I've tried the non-greedy character, but I must not be putting it in the right place.
What the above find RegEx matches is:
0: border:0;color:#000;width:auto;padding-top:0;margin:0;
1: color:#000;text-decoration:underline;font-size:12px;
2: color:#000;font-size:12px;padding:0;
While those are technically correct matches, I need it to match border:0;, color:#000;, etc separately for my replace to work.
Try this - use non-greedy matching. This works for me
(.+?):(.+?);
Forget the colon. Just replace all semicolons with ";\n".
In Javascript, for example, you could write:
text = text.replace(/;/gm,";\n");
I would further refine that to address leading-space issues, etc., but this will put every style rule on its own line.

Resources