PHP regex. How to get an array of matches? - php

I have a string in a format like this:
5;1-x;1-2;(1-x;)+
I used 1-x as a notation for all integers from 1 to infinity and (1-x;)+ to mark that the last integer may be repeated any number of times.
Some example strings:
5;1;1;1
5;7;2;7;5;1;9
How can I match these strings with regex and get all the (1-x;)+ matches?
I have tried the following:
preg_match_all('%5;([1-9]{1}[0-9]*);([1-2]);([1-9]{1}[0-9]*;?)+%',
$str, $matches);
And the result for string "5;1;1;1" is:
array(4) {
[0]=>
array(1) {
[0]=>
string(7) "5;1;1;1"
}
[1]=>
array(1) {
[0]=>
string(1) "1"
}
[2]=>
array(1) {
[0]=>
string(1) "1"
}
[3]=>
array(1) {
[0]=>
string(1) "1"
}
}
For the string "5;7;2;7;5;1;9" it is:
array(4) {
[0]=>
array(1) {
[0]=>
string(13) "5;7;2;7;5;1;9"
}
[1]=>
array(1) {
[0]=>
string(1) "7"
}
[2]=>
array(1) {
[0]=>
string(1) "2"
}
[3]=>
array(1) {
[0]=>
string(1) "9"
}
}
As you can see, only the last integer from (1-x;)+ is in the matches array, but I want the matches array to contain values 7, 5, 1, and 9, not just the last one. Is this even possible using regex or do I need to use another approach to validate and get values from these strings?

One way
//$str = "5;1;1;1";
$str = "5;7;2;7;5;1;9";
$pattern = '%^5;([1-9]\d*;)[12];((?:[1-9]\d*;?)+)$%';
$str = preg_replace( $pattern, '$1$2', $str, -1, $count );
if ( $count ) {
print_r( explode( ';', $str ) );
} else {
echo 'Invalid string';
}
The -1 means no limit to the number of replacements.
$count is the number of replacements made. It will be 1 if the string is valid, or 0 otherwise.
The above assumes a string is still valid if it ends in a ;.

I honestly would just explode the string and remove the unwanted first and third elements that like this:
$array = explode(';', $string);
$diff_array = array(0 => 'not_used', 2 => 'not_used');
$final_array = array_key_diff($array, $diff_array);
This gives you an array of all the values except the first and third elements which are the ones which you seem to not be interested in.
If you then need to verify that the remaining elements are indeed integers with value >= 1 you could run an array_filter on it like this:
$filtered_array = array_filter($final_array, function($value) {
if ((string)(int)$value == $value && (int)$value >= 1) return true;
return false;
}

Related

how to format array from string in php?

I want if the first number in the string is 2 the output will be 2 array. How to explode as each array from string.
My code
<?php
$str = "2,2;2;,1;1;,07-09-2016;07-09-2016;,08-09-2016;10-09-2016;,1;3;,100.00;450.00;";
$data = explode(',',$str);
$out = array();
for($i=1;$i < count($data)-1;$i++){
$out[]= explode(';',$data[$i]);
}
$i = $out[0][0];
foreach ($out as $key => $value) {
for($a=0;$a < $i; $a++){
echo $value[$a]. "<br/>";
}
}
?>
I get the result 221107-09-201607-09-201608-09-201610-09-201613
But I want this format
<?php
$str = "2,2;2;,1;1;,07-09-2016;07-09-2016;,08-09-2016;10-09-2016;,1;3;,100.00;450.00;";
//format will be split by semicomma ;
$arr1 = Array('2','1','07-09-2016','08-09-2016','1','100.00');
$arr2 = Array('2','1','07-09-2016','10-09-2016','3','450.00');
?>
The php function array_column will come in handy here. Here is short code example that should output what you are looking for.
<?php
//Your original input
$str = "2,2;2;,1;1;,07-09-2016;07-09-2016;,08-09-2016;10-09-2016;,1;3;,100.00;450.00";
//explode the array into its sub-arrays
$arrs = explode(",", $str);
//remove the first element that sets how many elements are in each array
$numArrs = array_shift($arrs);
//convert strings into those wanted sub-arrays
array_walk($arrs, function(&$val, $key) { $val = explode(';',$val); });
//make the answer we need
$ans = array();
for($i=0; $i<$numArrs; $i++) {
//array_column does all the work that we want, making life easy
$ans[] = array_column($arrs, $i);
}
var_dump($ans);
This process does assume the string is properly formatted for what we are looking for - it will fail horribly if that is not the case.
Use the explode() function! It's really cool.
Here's how I would solve this problem. You will end up with a 2d array with my code. You can access $arr1 with $fourthStep[0] and $arr2 with $fourthStep[1] etc...
<?php
$str = "2,2;2;,1;1;,07-09-2016;07-09-2016;,08-09-2016;10-09-2016;,1;3;,100.00;450.00;";
$fourthStep = array();
//First, let's split that string up into something a little more.. readable.
$firstStep = explode(",",$str);
//$firstStep[0] contains our count for the total array count.
foreach($firstStep as $secondStep){ //Our second step is to loop through the newly created array which splits each section of your array
if ($secondStep != $firstStep[0]){ //skip the first part, as that is only telling us of array count
$thirdStep = explode(";",$secondStep); //third step is to get each data part of each section. The count of this array should be 'firstStep[0]-1'
for($i = 0; $i<$firstStep[0]; $i++){
//Now we want to assign the values into a 2D array
$fourthStep[$i][count($fourthStep[$i])] = $thirdStep[$i];
}
}
}
var_dump($fourthStep);
?>
Result:
array(2) { [0]=> array(6) { [0]=> string(1) "2" [1]=> string(1) "1" [2]=> string(10) "07-09-2016" [3]=> string(10) "08-09-2016" [4]=> string(1) "1" [5]=> string(6) "100.00" } [1]=> array(6) { [0]=> string(1) "2" [1]=> string(1) "1" [2]=> string(10) "07-09-2016" [3]=> string(10) "10-09-2016" [4]=> string(1) "3" [5]=> string(6) "450.00" } }
Just for a further note, you don't need the '2' in the first part of your string to work out how many arrays to split it into, as they use 2 different seperators you can work it out quite easily. Save like 8 bits of space or somethin'

PHP - How to switch / reverse values in one column of 2D array

I have an exploded array and I am trying to reverse the first name and last name in a specific column.
Here is the array:
array(729) {
["ID;Position;Name;ER;FF;GA"]=>
array(24) {
[0]=>
string(3) "ID"
[1]=>
string(3) "Position"
[2]=>
string(4) "Name"
[3]=>
string(4) "ER"
[4]=>
string(6) "FF"
[5]=>
string(13) "GA"
}
["7702;Manager;Johnson, Bill;44.5;6T;406"]=>
array(24) {
[0]=>
string(4) "7702"
[1]=>
string(1) "Manager"
[2]=>
string(11) "Johnson, Bill"
[3]=>
string(3) "44.5"
[4]=>
string(4) "6T"
[5]=>
string(1) "406"
}
As you can see, I am need to flip the first name and last name in every 3rd element (index[2]). I was thinking to explode every 3rd element via ',' delimiter (since it is always fname, lname) and then use array_reverse to reverse them... and then reconstruct.
$dump_array = explode(PHP_EOL, $dump);
foreach($dump_array as $line){
$temp[$line]=explode(';', $line);
}
foreach($temp as $ele){
var_dump($temp[$ele]);
$temp[$ele]=array_reverse($temp[$ele[2]]); #I need to do another explode (',') somewhere?
}
You want to do implode instead of explode() in the last line or a sample demo code below :
foreach($dump as $line) {
$temp_str = $line[2];
$temp_str = explode(",", $temp_str);
$line[2] = $temp_str[1] . ", " . $temp_str[0];
}
How does it work: For every array, it picks that array out as $line and then explode the string stored in $line[2] and reverse their order and replace $line[2] with the new reversed value joined with a comma in middle of them
Here is the another way:
$temp = array("asjd", "first , last", "asdjlakd");
foreach($temp as $ele){
if (strpos($ele, ",")!== false){
$data = explode(",", $ele);#I need to do another explode (',') somewhere?
$reverse_data=array_reverse($data);
print_r($reverse_data);
}
}

Saparate array data with comma

I have an function that return an array
[0]=>
array(2) {
[0]=>
string(2) "22"
[1]=>
string(9) "Plantroom"
}
[1]=>
array(2) {
[0]=>
string(2) "22"
[1]=>
string(4) "dfdf"
}
}
sometime my array have one object or multiple .
[0]=>
array(2) {
[0]=>
string(2) "23"
[1]=>
string(4) "sec"
}
}
now I want to show my array data by comma separated.
like
for first array => Plantroom,dfdf
for second array =>sec
I am using this code but not work
my function
function area_name($game_id)
{
include_once('Model/Game.php');
$c2 = new Game();
$cd2 = $c2->Select_area($game_id);
return $cd2;
}
and call my function as
implode(", ", area_name($cd[$i][0]))
But my output show text Array
Because area_name() is not just returning an array, its returning an array of arrays. implode() will join the elements of the array that area_name() returns assuming they are strings, but those elements are also arrays and as such they are stringified to text "Array".
To obtain the desired output from implode() you would have to first generate an array with only the values you want from the structure returned by area_name().
For instance:
$data = array_map(function ($a) { return $a[1]; }, area_name($cd[$i][0]));
echo implode(', ', $data);

php regex to match key value pairs

I have a string like as below.
$string = "height=175cm weight=70kgs age=25yrs"
String contents are key value pairs each pair are separated by a Tab. I want each key value pairs as separate variable and prints out each.
I have tried with below code but i am not getting proper result please help me where i went wrong.
$string = "height=175cm weight=70kgs age=25yrs";
$pattern = "(([^=]*)\s*=\s*(.*))";
if (preg_match($pattern,$string,$match)) {
echo "<pre>";
print_r($match);
} else {
echo "not matche\n";
}
Result:
Array
(
[0] => height=175cm weight=70kgs age=25yrs
[1] => height
[2] => 175cm weight=70kgs age=25yrs
)
You can use this code:
$string = "height=175cm weight=70kgs age=25yrs";
if (preg_match_all('/\s*([^=]+)=(\S+)\s*/', $string, $matches)) {
$output = array_combine ( $matches[1], $matches[2] );
print_r($output);
}
OUTPUT:
Array
(
[height] => 175cm
[weight] => 70kgs
[age] => 25yrs
)
You can use this:
$string = "height=175cm weight=70kgs age=25yrs";
$pattern = "/(\w+)=(\d+)(\w+)/i";
if(preg_match_all($pattern,$string,$match))
{
var_dump($match);
}
Result:
array(4) {
[0]=>
array(3) {
[0]=>
string(12) "height=175cm"
[1]=>
string(12) "weight=70kgs"
[2]=>
string(9) "age=25yrs"
}
[1]=>
array(3) {
[0]=>
string(6) "height"
[1]=>
string(6) "weight"
[2]=>
string(3) "age"
}
[2]=>
array(3) {
[0]=>
string(3) "175"
[1]=>
string(2) "70"
[2]=>
string(2) "25"
}
[3]=>
array(3) {
[0]=>
string(2) "cm"
[1]=>
string(3) "kgs"
[2]=>
string(3) "yrs"
}
}
I've pasted a code sample below which helps you to solve your problem. Certainly, it is not very tightly compressed and has quite a few more lines of code than the other answers (which are all good answers!).
The reason I did this was because it looks like you may benefit from an explanation that takes you one step at a time in the progression of solving your problem, so that you can understand what is happening along the way.
Here's the code you can use:
<?php
$string = "height=175cm\tweight=70kgs\tage=25yrs";
// Divide your string into an array, with each element
// in the array being a string with a key-value pair
$pairs = explode("\t", $string);
// See what the array of pair strings looks like.
// print_r($pairs);
// Create an array to get it ready to hold key-value pairs.
$results = array();
// For each string in your array, split at the equal sign
// and set values in the $results array.
foreach ($pairs as $pair) {
$exploded_pair = explode("=", $pair);
// See what each exploded pair array looks like.
// print_r($exploded_pair);
$key = $exploded_pair[0];
$value = $exploded_pair[1];
$results[$key] = $value;
}
print_r($results);
Instead of using regular expressions, this makes use of the explode function in PHP. You can read the documentation on explode found here.
You said that your input string is separated by tabs, which is why the assignment statement for $string has \t instead of spaces. If you were to use spaces instead of tabs, then make sure that you change
$pairs = explode("\t", $string);
to
$pairs = explode(" ", $string);

Regex to match certain pattern of number combinations

I'm looking making a regex in php that gets data from the following format:
"1,2,3;7,1,3;1" returns an $matches array with "(1,2,3,7,1,3,1)"
"1" returns an $matches with "(1)"
"1;1;3;5;7;10;999" returns an $matches array with "(1,1,3,5,7,10,999)"
"1,1,1;2,5;3,4" doesn't pass since numbers are repeating within semicolon boundaries
"2,3,4;5,;" doesn't pass since it doesn't satisfy the format.
(Quotes in the examples are there to make them easier to read; they should not appear in the real results.)
The format is digit numbers separated by either commas or semicolons and within semicolons they don't repeat each other. It should not accept any other format.
I tried /(^(\d{1,3})$)|(([0-9]+)([,|;]{1}[0-9]+)+)/ but it didn't work.
I also tried /[0-9]+([,|;]{1}[0-9]+)+/ but it didn't worked either. When I got the $matches array it didn't have the values I needed as depicted above.
I'm doing this in PHP 5.2.
Thanks.
This particular problem has too much logic for regular expressions to be practical; this is how you could solve it with regular code:
// reduction function - keeps merging comma separated arguments
// until there's a duplicate or invalid item
function join_unique(&$result, $item)
{
if ($result === false) {
return false;
}
$items = explode(',', $item);
$numbers = array_filter($items, 'is_numeric');
if (count($items) != count($numbers)) {
return false;
}
$unique = array_unique($numbers);
if (count($unique) != count($numbers)) {
return false;
}
return array_merge($result, $numbers);
}
// main function - parse a string of comma / semi-colon separated values
function parse_nrs($str)
{
return array_reduce(explode(';', $str), 'join_unique', array());
}
var_dump(parse_nrs('1,2,3;7,1,3;1'));
var_dump(parse_nrs('1'));
var_dump(parse_nrs('1;1;3;5;7;10;999'));
var_dump(parse_nrs('1,1,1;2,5;3,4'));
var_dump(parse_nrs('2,3,4;5,;'));
Output:
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
[3]=>
string(1) "7"
[4]=>
string(1) "1"
[5]=>
string(1) "3"
[6]=>
string(1) "1"
}
array(1) {
[0]=>
string(1) "1"
}
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
[2]=>
string(1) "3"
[3]=>
string(1) "5"
[4]=>
string(1) "7"
[5]=>
string(2) "10"
[6]=>
string(3) "999"
}
bool(false)
bool(false)
See also: array_reduce() array_unique()
It is impossible to do this in a single step. First you will need to check for the requirement of numbers repeating within a semicolon boundary, and then if it passes that checks split the string.
For example:
if (!preg_match('/\b(\d+),[^;]*\b\1\b/', $string)) {
$matches = preg_split('/[,;]/', $string);
} else {
$matches = NULL;
}
Ideone: http://ideone.com/Y8xf1N

Categories