positive lookahead in css
You cannot yet declare which part of the selector is the subject. The subject is always the last element of the selector in CSS, until we get the power to move that, likely using the $
or !
syntax.
// Always selects the .specialClass div which follows another div
div + div.specialClass {
color: red;
}
In the future, you'll be able to make the first div the subject, likely with the following syntax:
// Selects any `div` preceding any `div.specialClass`
$div + div.specialClass { // or maybe div! + div.specialClass
color: red;
}
Your only workaround in the interim is to use JavaScript. A tool like jQuery would make this very trivial:
$("div + div.specialClass").prev();
Which is now a reference to all div
elements immediately preceding any div.specialClass
.
Demo: http://jsfiddle.net/jonathansampson/HLfCr/
Source: http://dev.w3.org/csswg/selectors4/#subject
Regex negative lookbehind and lookahead: equivalence and performance
Is it going to have an impact on performances?
In most cases, the more steps a regex needs to find a match, the slower the performance is. Although it also depends what platform you will use the regex in later (say, if you test a regex for use in .NET using regex101.com, it does not mean it will cause a catastrophic backtracking with a lazy dot matching regex failing with a long text).
Are the two regex really functionally equivalent?
No, they aren't. (?<!\.png|\.css)$
finds an end of the line that is not preceded with .png
or .css
. ^(?!.*[.]png|.*[.]css$).*$
finds lines that do not contain .png
or the lines that do not end with .css
. To make them "equivalent" (that is, if you want to make sure the lines ending with .png
or .css
are not matched), use
^(?!.*[.](?:png|css)$).*$
^^^^^^^^^^^^
Make sure the $
is checked after both png
and css
in the negative lookahead.
There will still be the difference between the regexps: the first will just match the end of the line, and the second will match the whole line.
Is there a way to speed up the lookbehind solution?
Note that the lookbehind in Pattern 1 is checked at each location inside the string. The lookahead in Pattern 2 is only checked once, at the very beginning of the string. That is why an anchored lookahead solution will be faster UNDER one condition - if you cannot use a RightToLeft modifier that is only available in few regex flavors (e.g. .NET).
The $(?<!\.(?:png|css)$)
lookbehind solution is faster than Pattern 1 because the lookbehind pattern is checked just once, after reaching the end of string/line. Still, this takes a bit more steps because of the implementation of a lookbehind that is costlier than a lookahead.
To really find out which solution is fastest, you need to set up performance tests in your environment.
Regex positive lookbehind alternative for word wrap
Use
return text.replace(/(.{45})(?!$)/g, "$1\r\n");
See regex proof.
EXPLANATION
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
.{45} any character except \n (45 times)
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
(?! look ahead to see if there is not:
--------------------------------------------------------------------------------
$ before an optional \n, and the end of
the string
--------------------------------------------------------------------------------
) end of look-ahead
regex replace to match url() paths in css and replace with asset_path
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 matchurl ('
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.
What are non-word boundary in regex (\B), compared to word-boundary?
A word boundary (\b
) is a zero width match that can match:
- Between a word character (
\w
) and a non-word character (\W
) or - Between a word character and the start or end of the string.
In Javascript the definition of \w
is [A-Za-z0-9_]
and \W
is anything else.
The negated version of \b
, written \B
, is a zero width match where the above does not hold. Therefore it can match:
- Between two word characters.
- Between two non-word characters.
- Between a non-word character and the start or end of the string.
- The empty string.
For example if the string is "Hello, world!"
then \b
matches in the following places:
H e l l o , w o r l d !
^ ^ ^ ^
And \B
matches those places where \b
doesn't match:
H e l l o , w o r l d !
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
Positive lookahead + overlapping matches regex
I only tried this on regex101 (marked golang regex), but it seems that it works as expected:
%[0-9a-fA-F][0-9a-fA-F]|(%)
or simpler:
%[0-9a-fA-F]{2}|(%)
Range vs character in Negative lookbehind in regex
Lets first take a look at what your regex does:
(?!a)
check that the next character is not ana
\d*
match any amount of digits(?=c)
check that the next character is ac
In this one, the (?!a)
is rather pointless, as the next character is a digit or c
according to the rest of the pattern. (e.g. it will also split b1c
into b
and c
) You might have been looking for a lookbehind (not supported in JS) (?<=a)
to check that the previous character was an a
.
According to your comment you seem to be confusing negative lookahead (?!pattern)
and (positive) lookbehind (?<=pattern)
The second regex is quite similar, except that you check for generic (lowercase) letters instead of certain ones. If there is no digit in between those letters (ac
), one can simplify your regex to (?![a-z])(?=[a-z])
(?![a-z])
check that the next character is no letter(?=[a-z])
check that the next character is a letter
This can never be true.
Optional whitespaces inside lookbehind regex
Do not use lookbehinds when you can do it easily with a capturing group.
In your case you can do something like:
(\bfont-size:\s*)([0-9]+)
Then use the capturing groups $1
and $2
as you need.
Notepad++ Regex Find/Replace Using Look Behind not Working
Based on comments to the original question here are some work-arounds that solved my problem.
Option #1
Replace the lookbehind portion of the regex statement (?<=[\s,;])
with a simple non-lookbehind group matching statement such as ([\s,;])
. This will continue to limit search results to strings beginning with the specified characters in the lookbehind. The only caveat is that in my replacement string e.g. $1 $2
I would need to leave out the undesired matched characters that should not be a part of the replacement string.
Option #2
Use the "Replace All" button. It will perform replacements correctly when using a positive lookbehind in your regex statement as opposed to using the "Replace" button for single replacement.
I went with Options #1 only because it achieves what I need while allowing me to still perform a single replacement at a time. With larger documents I don't want to use "Replace All" until I have thoroughly tested my regex expression.
Firefox bug with regex positive lookaheads?
I'm guessing that maybe you might want to write a simple expression that'd be somewhat similar to:
\s*(<[^>]*>)\s*
Demo 1or
\s{0,1}(<[^>]*>)\s{0,1}
Demo 2and replace it with $1
.
const regex = /\s{0,1}(<[^>]*>)\s{0,1}/g;const str = `this is <some> test`;const subst = `$1`;
const result = str.replace(regex, subst);
console.log(result);
Related Topics
Systematically Resolve Conflicting Styles in CSS
Floated Image to Left of a Ul Is Ignoring Margin/Padding
Using a General Purpose Selector as a Mixin in Less CSS
Nuxt & Vuetify: How to Control The Order in Which CSS Files Are Loaded
CSS - Border Radius and Solid Border Curved Inside
How to Center Text Inside: Before Pseudo Element
How to Create Nested Loops with Less CSS
Material-Ui Style Dialog/Modal Backdrop
Make Entire CSS Sheet !Important
What Does Mean /*! Some Url or Text */ in CSS
Stop Div Resizing Parent Div Using CSS
Make Background Image Responsive
CSS - Horizontal Navigation List Items to Fill All Available Space
CSS Col Visibility:Collapse Does Not Work on Chrome
Setting Listview <Li> Height in Jquery Mobile
Display Only The Number of Items That Will Fit, and Then Expand to Fit Snugly