Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PCRE regular expression overlapping matches

Tags:

regex

php

i have the following string

001110000100001100001

and this expression

/[1]....[1]/g

this makes two matches

matches

but i want it to also match the pattern between those both with lookbehind so to say, the overlapping 1

i have absolutely no clue, how can this work ? instead of 0 it can be any characters

like image 426
john Smith Avatar asked Feb 17 '16 13:02

john Smith


People also ask

Can regex matches overlap?

You can use the new Python regex module, which supports overlapping matches.

How to find overlapping matches regex Python?

To find overlapping matches with a regex with Python, we can use the re. finall method with the r'(? =(\w\w))' regex string.

What are non overlapping matches?

This will return an array of all non-overlapping regex matches in the string. “Non-overlapping” means that the string is searched through from left to right, and the next match attempt starts beyond the previous match.


2 Answers

A common trick is to use capturing technique inside an unanchored positive lookahead. Use this regex with preg_match_all:

(?=(1....1))

See regex demo

The values are in $matches[1]:

$re = "/(?=(1....1))/"; 
$str = "001110000100001100001"; 
preg_match_all($re, $str, $matches);
print_r($matches[1]);

See lookahead reference:

Lookaround actually matches characters, but then gives up the match, returning only the result: match or no match. That is why they are called "assertions". They do not consume characters in the string, but only assert whether a match is possible or not.

If you want to store the match of the regex inside a lookahead, you have to put capturing parentheses around the regex inside the lookahead, like this: (?=(regex)).

like image 199
Wiktor Stribiżew Avatar answered Oct 28 '22 11:10

Wiktor Stribiżew


You can also do it using the \K feature (that refers to where the returned result begins) inside a lookbehind:

(?<=\K1)....1

demo

This way, you don't need to create a capture group, and since all characters are consumed (except the first that is in the lookbehind), the regex engine doesn't have to retry the pattern for the next five positions after a success.

$str = '001110000100001100001';

preg_match_all('~ (?<= \K 1 ) .... 1 ~x', $str, $matches);

print_r($matches[0]);

code

Note that if you are sure the second character is always a zero, using 0(?<=\K10)...1 is more performant because the pattern starts with a literal character and pcre is able to optimize it with a quick search of possible positions in the subject string.

like image 42
Casimir et Hippolyte Avatar answered Oct 28 '22 12:10

Casimir et Hippolyte