Reputation: 495
I am having a difficult time getting my regular expression code to work properly in PHP. Here is my code:
$array = array(); // Used to satisfy the 3rd argument requirment of preg_match_all.
$regex = '/(012|345|678|987|654|321|123|456|789|876|543|210|234|567|765|432)/';
$subject = '123456';
echo preg_match_all($regex, $subject, $array).'<br />';
print_r($array);
When this code is ran it will output:
2
Array
(
[0] => Array
(
[0] => 123
[1] => 456
)
[1] => Array
(
[0] => 123
[1] => 456
)
)
What can I do so that it will match 123, 234, 345 and 456?
Thanks in advance!
Upvotes: 2
Views: 483
Reputation: 75242
$regex = '/(?=(012|345|678|987|654|321|123|456|789|876|543|210|234|567|765|432))/';
$subject = '123456';
preg_match_all($regex, $subject, $array);
print_r($array[1]);
output:
Array
(
[0] => 123
[1] => 234
[2] => 345
[3] => 456
)
You're trying to retrieve matches that overlap each other in the subject string, which in general is not possible. However, in many cases you can fake it by wrapping the whole regex in a capturing group, then wrapping that in a lookahead. Because the lookahead doesn't consume any characters when it matches, the regex engine manually bumps forward one position after each successful match, to avoid getting stuck in an infinite loop. But capturing groups still work, so you can retrieve the captured text in the usual way.
Notice that I only printed the contents of the first capturing group ($array[1]
). If I had printed the whole array of arrays ($array
), it would have looked like this:
Array
(
[0] => Array
(
[0] =>
[1] =>
[2] =>
[3] =>
)
[1] => Array
(
[0] => 123
[1] => 234
[2] => 345
[3] => 456
)
)
Upvotes: 1
Reputation: 85358
Yeah it's a hack but you can use RegEx
<?php
$subject = '123456';
$rs = findmatches($subject);
echo '<pre>'.print_r($rs,true).'</pre><br />';
function findmatches($x) {
$regex = '/(\d{3})/';
// Loop through the subject string
for($counter = 0; $counter <= strlen($x); $counter++) {
$y = substr($x, $counter);
if(preg_match_all($regex, $y, $array)) {
$rs_array[$counter] = array_unique($array);
}
}
// Parse results array
foreach($rs_array as $tmp_arr) {
$rs[] = $tmp_arr[0][0];
}
return $rs;
}
?>
Returns:
Array
(
[0] => 123
[1] => 234
[2] => 345
[3] => 456
)
NOTE: This would only work with concurrent numbers
Upvotes: 0
Reputation: 4612
It can be done with regular expressions. The problem with your original code is that as soon as a match occurs, the character is consumed and the regular expression will not backtrack. Here's one way to do it:
$array = array(); // Used to satisfy the 3rd argument requirment of preg_match_all.
$regex = '/012|345|678|987|654|321|123|456|789|876|543|210|234|567|765|432/';
$subject = '123456';
$tempSubject = $subject;
$finalAnswer = array();
do {
$matched = preg_match($regex, $tempSubject, $array);
$finalAnswer = array_merge($finalAnswer, $array);
$tempSubject = substr($tempSubject, 1);
} while ($matched && (strlen($tempSubject >= 3)));
print_r($finalAnswer);
As suggested in another answer, however, regular expressions might not be the correct tool to use in this situation, depending on your larger goal. In addition, the above code may not be the most efficient way (wrt memory or wrt performance) to solve this with regular expressions. It's just a striaghtforward fulfill-the-requirement solution.
Upvotes: 0
Reputation: 48887
Regex is not the right tool for this job (it's not going to return "sub-matches"). Simply use strpos
in a loop.
$subject = '123456';
$seqs = array('012', '345', '678', '987', '654', '321', '123', '456', '234');
foreach ($seqs as $seq) {
if (strpos($subject, $seq) !== false) {
// found
}
}
Upvotes: 2