PHP SPL RegexIterator removes unmatched elements from array - php

I have array with some strings and i want to use RegexIterator to replace some stuff on matched string but to also leave un-matched strings in array.
Here is my code:
$a = new ArrayIterator(array('LeaveThisInArray','value1', 'value2'));
$i = new RegexIterator($a, '/^(value)(\d+)/', RegexIterator::REPLACE);
$i->replacement = '$2:$1';
print_r(iterator_to_array($i));
And i get this as output:
Array
(
[0] => 1:value
[1] => 2:value
)
But what i wanted is this:
Array
(
[0] => LeaveThisInArray
[1] => 1:value
[2] => 2:value
)
Is there any flag i can set or something, because i cant find much in the spl documentation.

You can try with preg_replace
sample code:
$re = "/^(value)(\\d+)/m";
$str = "LeaveThisInArray\nvalue1\nvalue2";
$subst = '$2:$1';
$result = preg_replace($re, $subst, $str);
Here is online demo
Try with ^(value)(\d*) in your existing code.

The closest I can think about for this right now is like this:
$a = new ArrayIterator(array('LeaveThisInArray','value1', 'value2'));
$i = new RegexIterator($a, '/^(?:(value)(\d+))?/', RegexIterator::REPLACE);
$i->replacement = '$2$1';
print_r(iterator_to_array($i));

Related

Merge data into an array then count the array values

I need to merge data into an array, then count the array values.
$str = '"Cat","A","A","A","A"';
$abc = [
$str,
"A",
"Cat",
"Dog",
"A",
"Dog"
];
print_r(array_count_values($abc));
Result came out:
Array ( ["Cat","A","A","A","A"] => 1 [A] => 2 [Cat] => 1 [Dog] => 2 )
But I need like this way:
Array ( [A] => 6 [Cat] => 2 [Dog] => 2 )
This is because $str is a string and not an array. So this is added into the $abc array as one element.
You can convert in into an array with the explode function:
$str = '"Cat","A","A","A","A"';
$arr = explode(',', $str);
// So $arr is Array([0] => "Cat", [1] => "A", [2] => "A", [3] => "A", [4] => "A")
Then you need to remove the double quotes around each element.
I suggest to use the trim function, and the array_map, to apply it to each element:
$arr = array_map(function ($item) { return trim($item, '"'); }, $arr);
// $arr is Array([0] => Cat, [1] => A, [2] => A, [3] => A, [4] => A)
Then you can merge it with the rest of values:
$abc = array_merge($arr, array("A","Cat","Dog","A","Dog"));
print_r(array_count_values($abc));
// Should be Array ( [A] => 6 [Cat] => 2 [Dog] => 2 )
Well, then, don't put a string into an array and expect it to be treated as array values. Either modify the string to be an array, and merge the two arrays, or parse the string and add each value to the array.
For the latter approach, you can do something like:
$str = '"Cat","A","A","A","A"';
$abc = array("A","Cat","Dog","A","Dog");
$splitstr = explode(',',str_replace('"','',$str));
$finalarray = array_merge($abc,$splitstr);
print_r(array_count_values($finalarray));
Your logic is flawed, you should first create array properly
$str = '"Cat","A","A","A","A"';
$abc = array("A","Cat","Dog","A","Dog");
$splitstr = explode(',',str_replace('"','',$str));
$finalarray = array_merge($abc,$splitstr);
print_r(array_count_values($finalarray));
Now you will get the desired result.
Because your quote-wrapped, comma-delimited string closely resembles a json string, I reckon it will be most direct/performant to just wrap the whole string in square braces, then json_decode it and spread it into the array (so that elements are injected into the array one at a time).
Code: (Demo)
$str = '"Cat","A","A","A","A"';
$abc = [
...json_decode("[$str]"),
"A",
"Cat",
"Dog",
"A",
"Dog"
];
print_r(array_count_values($abc));
you put first element as string completely. make it separate
$str = '"Cat","A","A","A","A"';
$abc=array( "Cat","A","A","A","A", "A","Cat","Dog","A","Dog");
print_r(array_count_values($abc));
Or merge array
$arr1 = ["Cat","A","A","A","A"];
$abc=array_merge( $arr1,["A","Cat","Dog","A","Dog"]);
print_r(array_count_values($abc));
Demo
You are using array_count_values to count all the values of the $abc array. However, $str is a string and not an array, but an element of the $abc array.
The simplest solutions is to convert $str into an array by removing " double quotes (with str_replace method) and splitting substrings using , as a delimiter (with explode method). This can be done just by adding a single line as shown in this snippet:
$str = '"Cat","A","A","A","A"';
// Converts $str into an array of strings
$str_array = explode(',',str_replace('"','',$str));
$abc = array_merge($str_array, array("A","Cat","Dog","A","Dog"));
print_r(array_count_values($abc));
You can see the execution of this script in this link.
According to the PHP manual, you can use array_merge ( array $array1 [, array $... ] )
example:
$str = '"Cat","A","A","A","A"';
$abc=array_merge($str, array("A","Cat","Dog","A","Dog"));
print_r(array_count_values($abc));

How can I split a semicolon delimited string into separate item from string?

I need to split my string input into an semicolon separate as below.
Original String: Loganathan <logu#gmail.com>; Nathan <nathan#gmail.com>; Tester <tester#gmail.com>;
I need split like
Loganathan, logu#gmail.com
Nathan, nathan#gmail.com
Tester, tester#gmail.com
How can I go about accomplishing this?
You can use explode function. explode link
$str = "Loganathan <logu#gmail.com>; Nathan <nathan#gmail.com>; Tester <tester#gmail.com>;";
$str = str_replace(array(" <",">"),array(", ",""),$str);
$converted = explode(";",$str);
print_r($converted);
Which gives you output like
Array(
[0] => Loganathan, logu#gmail.com
[1] => Nathan, nathan#gmail.com
[2] => Tester, tester#gmail.com
)
Use explode
$str = 'Loganathan <logu#gmail.com>; Nathan <nathan#gmail.com>; Tester <tester#gmail.com>;';
//Removing the "<>" symbols
$str = str_replace("<",",",$str);
$str = str_replace(">","",$str);
$result = explode(";", $str);
print_r(array_filter($result)); //Removing empty array values
Result:
Array
(
[0] => Loganathan ,logu#gmail.com
[1] => Nathan ,nathan#gmail.com
[2] => Tester ,tester#gmail.com
)

How to form two arrays from string separated by "," and followed by -?

$str="a,b,c,d-e,f,g,h"
I am trying to extract the strings from $str that are separated "," and are before "-" in one array and the strings separated by "," and are after "-" in second array. So that $arr1=array(a,b,c,d); and $arr2=array(e,f,g,h);. I am just using $str as an example and generally I want this to work for any string of the same form i.e. $str=s1,s2,s3,s4,s5,....-r1,r2,t3....
NOTE: If $str doesn't have "-" then $arr2 vanishes and $arr1 contains an array of the elements separated by ',' in $str.
This is what I tried
preg_match_all('~(^|.*,)(.*)(,.*|\-|$)~', $str, $arr1);
preg_match_all('~(-|.*,)(.*)(,.*|$)~', $str, $arr2);
However each array comes with one element that contains the string str.
Does anyone know why this is not working.
All of your regex patterns are not optimal and it seems the task is easier to solve with explode and array_map:
array_map() returns an array containing all the elements of array1 after applying the callback function to each one. The number of parameters that the callback function accepts should match the number of arrays passed to the array_map()
$str="a,b,c,d-e,f,g,h";
$ex = array_map(function ($s) {
return explode(",", $s);
}, explode("-", $str));
print_r($ex);
See IDEONE demo
Results:
Array
(
[0] => Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
[1] => Array
(
[0] => e
[1] => f
[2] => g
[3] => h
)
)
^(.*?(?=-|$))|(?<=-)(.*$)
You can use this to get 2 arrays.See demo.
https://regex101.com/r/vV1wW6/19
Your regex is not working as you have used greedy modifier..*, will stop at the last instance of ,
EDIT:
Use this is you want string after - to be in second group.
^(.*?(?=-|$))(?:-(.*$))?
https://regex101.com/r/vV1wW6/20
You can simply use preg_match to check does your string contains - if yes than can simply use array_walk like as
$str = 'a,b,c,d-e,f,g,h';
$result = [];
if(preg_match('/[-]/', $str)){
array_walk(explode('-',$str),function($v,$k)use(&$result){
$result[] = explode(',',$v);
});
}else{
array_walk(explode(',',$str),function($v,$k)use(&$result){
$result[] = $v;
});
}
print_r($result);
Without regex (the most reasonable way):
$str="a,b,c,d-e,f,g,h";
list($arr1, $arr2) = explode('-', $str);
$arr1 = explode(',', $arr1);
if ($arr2)
$arr2 = explode(',', $arr2);
else
unset($arr2);
With regex (for the challenge):
if (preg_match_all('~(?:(?!\G)|\A)([^-,]+)|-?([^,]+),?~', $str, $m)) {
$arr1 = array_filter($m[1]);
if (!$arr2 = array_filter($m[2]))
unset($arr2);
}

how to find does not match item by regular expression

I have comma separated values in my table column and I have to separate new values from the old ones.
My code is
$a = '1,2,3,4';
$b = '1,2';
if(preg_match("/[^$b]/",$a,$matches)){
print_r($matches);
};
I want to find 3,4 , but I can't do it.
You really shouldn't use regular expressions for that. PHP has good functions to calculate intersections:
$a = explode(',', '1,2,3,4');
$b = explode(',', '1,2');
print_r(array_values(array_diff($a, $b)));
See also: array_diff()
Note that this would also work for the following example:
$a = '1,2,3,4';
$b = '1,3';
// outcome must be: 2, 4
use preg_match_all instead of preg_match
$a = '1,2,3,4,10';
$b = '1,2';
if(preg_match_all("/[^$b](.*)/",$a,$matches)){
print_r($matches);
};
output
Array
(
[0] => Array
(
[0] => 3,4,10
)
[1] => Array
(
[0] => ,4,10
)
)

Regex to find sequential integers

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!
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
}
}
$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
)
)
see it in action on ideone
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.
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

Categories