PHP from string to multiple arrays at the hand of placeholders - php

Good day,
I have an I think rather odd question and I also do not really know how to ask this question.
I want to create a string variable that looks like this:
[car]Ford[/car]
[car]Dodge[/car]
[car]Chevrolet[/car]
[car]Corvette[/car]
[motorcycle]Yamaha[/motorcycle]
[motorcycle]Ducati[/motorcycle]
[motorcycle]Gilera[/motorcycle]
[motorcycle]Kawasaki[/motorcycle]
This should be processed and look like:
$variable = array(
'car' => array(
'Ford',
'Dodge',
'Chevrolet',
'Corvette'
),
'motorcycle' => array(
'Yamaha',
'Ducati',
'Gilera',
'Kawasaki'
)
);
Does anyone know how to do this?
And what is it called what I am trying to do?
I want to explode the string into the two arrays. If it is a sub array
or two individual arrays. I do not care. I can always combine the
latter if I wish so.
But from the above mentioned string to two arrays. That is what I
want.
Solution by Dlporter98
<?php
///######## GET THE STRING FILE OR DIRECT INPUT
// $str = file_get_contents('file.txt');
$str = '[car]Ford[/car]
[car]Dodge[/car]
[car]Chevrolet[/car]
[car]Corvette[/car]
[motorcycle]Yamaha[/motorcycle]
[motorcycle]Ducati[/motorcycle]
[motorcycle]Gilera[/motorcycle]
[motorcycle]Kawasaki[/motorcycle]';
$str = explode(PHP_EOL, $str);
$finalArray = [];
foreach($str as $item){
//Use preg_match to capture the pieces of the string we want using a regular expression.
//The first capture will grab the text of the tag itself.
//The second capture will grab the text between the opening and closing tag.
//The resulting captures are placed into the matches array.
preg_match("/\[(.*?)\](.*?)\[/", $item, $matches);
//Build the final array structure.
$finalArray[$matches[1]][] = $matches[2];
}
print_r($finalArray);
?>
This gives me the following array:
Array
(
[car] => Array
(
[0] => Ford
[1] => Dodge
[2] => Chevrolet
[3] => Corvette
)
[motorcycle] => Array
(
[0] => Yamaha
[1] => Ducati
[2] => Gilera
[3] => Kawasaki
)
)
The small change I had to make was:
Change
$finalArray[$matches[1]] = $matches[2]
To:
$finalArray[$matches[1]][] = $matches[2];
Thanks a million!!

There are many ways to convert the information in this string to an associative array.
split the string on the new line into an array using the explode function:
$str = "[car]Ford[/car]
[car]Dodge[/car]
[car]Chevrolet[/car]
[car]Corvette[/car]
[motorcycle]Yamaha[/motorcycle]
[motorcycle]Ducati[/motorcycle]
[motorcycle]Gilera[/motorcycle]
[motorcycle]Kawasaki[/motorcycle]";
$items = explode(PHP_EOL, $str);
At this point each delimited item is now an array entry.
Array
(
[0] => [car]Ford[/car]
[1] => [car]Dodge[/car]
[2] => [car]Chevrolet[/car]
[3] => [car]Corvette[/car]
[4] => [motorcycle]Yamaha[/motorcycle]
[5] => [motorcycle]Ducati[/motorcycle]
[6] => [motorcycle]Gilera[/motorcycle]
[7] => [motorcycle]Kawasaki[/motorcycle]
)
Next, loop over the array and pull out the appropriate pieces needed to build the final associative array using the preg_match function with a regular expression:
$finalArray = [];
foreach($items as $item)
{
//Use preg_match to capture the pieces of the string we want using a regular expression.
//The first capture will grab the text of the tag itself.
//The second capture will grab the text between the opening and closing tag.
//The resulting captures are placed into the matches array.
preg_match("/\[(.*?)\](.*?)\[/", $item, $matches);
//Build the final array structure.
$finalArray[$matches[1]] = $matches[2]
}
The following is an example of what will be found in the matches array for a given iteration of the foreach loop.
Array
(
[0] => [motorcycle]Gilera[
[1] => motorcycle
[2] => Gilera
)
Please note that I use the PHP_EOL constant to explode the initial string. This may not work if the string was pulled from a different operating system than the one you are running this code on. You may need to replace this with the actual end of line characters that is being used by the string.

Why don't you create two separate arrays?
$cars = array("Ford", "Dodge", "Chevrolet", "Corvette");
$motorcycle = array("Yamaha", "Ducati", "Gilera", "Kawasaki");
You could also use an Associative array to do this.
$variable = array("Ford"=>"car", "Yamaha"=>"motorbike");

Related

capturing group under capturing group?

Is possible to capturing group under capturing group so i can have an array like that
regex = (asd1).(lol1),(asd2).(asd2)
string = asd1.lol1,asd2.lol2
return_array[0]=>group[0]='asd1';
return_array[0]=>group[1]='lol1';
return_array[1]=>group[0]='asd2';
return_array[1]=>group[1]='lol2';
While using regular expressions can get what you want, you could also use strtok() to iterate through what seems to simply be comma separated sets:
$results = array();
$str = 'asd1.lol1,asd2.lol2';
$token = strtok($str, ',');
while ($token !== false) {
$results[] = explode('.', $token, 2);
$token = strtok(',');
}
Output:
Array
(
[0] => Array
(
[0] => asd1
[1] => lol1
)
[1] => Array
(
[0] => asd2
[1] => lol2
)
)
With regular expressions your pattern needs to only include the two terms surrounding a period, i.e.:
$pattern = '/(?<=^|,)(\w+)\.(\w+)/';
preg_match_all($pattern, $str, $result, PREG_SET_ORDER);
The (?<=^|,) is a look-behind assertion; it makes sure to only match what comes after if preceded by either the start of your search string or a comma, but it doesn't "consume" anything.
Output:
Array
(
[0] => Array
(
[0] => asd1.lol1
[1] => asd1
[2] => lol1
)
[1] => Array
(
[0] => asd2.lol2
[1] => asd2
[2] => lol2
)
)
You're probably looking for preg_match_all.
$regex = '/^((\w+)\.(\w+)),((\w+)\.(\w+))$/';
$string = 'asd1.lol1,asd2.lol2';
preg_match_all($regex, $string, $matches);
This function will create a 2-dimensional array, where the first dimension represents the matched groups (i.e. the parentheses, 0 contains the whole matched string though) and each have subarrays to all the matched lines (only 1 in this case).
[0] => ("asd1.lol1,asd2.lol2") // a view of $matches
[1] => ("asd1.lol1")
[2] => ("asd1")
[3] => ("lol1")
[4] => ("asd2.lol2")
[5] => ("asd2")
[6] => ("lol2")
Your best bet to have groups is to process the first dimension of the array that you want and to then process them further, i.e. get "asd1.lol1" from 1 and 4 and then process these further into asd1 and lol1.
You wouldn't need as many parentheses in your first run:
$regex = '/^(\w+\.\w+),(\w+\.\w+)$/';
will yield:
[0] => ("asd1.lol1,asd2.lol2")
[1] => ("asd1.lol1")
[2] => ("asd2.lol2")
Then you can split the array in 1 and 2 into more granular values.
Flags can be set to preg_match_all to order the output differently. Particularly, PREG_SET_ORDER allows you to have all matched instances in the same subarray. This is of little importance if you're only processing one string, but if you're matching a pattern in a text, it might be more convenient to have all info about one match in $matches[0], and so forth.
Note that if you're just separating a string by comma and then by any periods, you might not need regular expressions and could conveniently use explode() as so:
$string = 'asd1.lol1,asd2.lol2';
$matches = explode(',', $string);
foreach($matches as &$match) {
$match = explode('.', $match);
}
This will give you exactly what you want, but do note that you don't have as much control over the process as with regular expressions – for instance, asd1.lol1.lmao,asd2.lol2.rofl.hehe will also work and they'll produce bigger arrays than you may want. You can check with count() on the size of the subarray and handle the cases when the array isn't of the appropriate size, though. I still believe that's more comfortable than using regular expressions.

Splitting GET string

I need to split my GET string into some array. The string looks like this:
ident[0]=<IDENT_0>&value[0]=<VALUE_0>&version[0]=<VERSION_0>&....&ident[N]=<IDENT_N>&value[N]=<VALUE_N>&version[N]=<VERSION_N>
So, I need to split this string by every third ampersand character, like this:
ident[0]=<IDENT_0>&value[0]=<VALUE_0>&version[0]=<VERSION_0>
ident[1]=<IDENT_1>&value[1]=<VALUE_1>&version[1]=<VERSION_1> and so on...
How can I do it? What regular expression should I use? Or is here some better way to do it?
There is a better way (assuming this is data being sent to your PHP page, not some other thing you're dealing with).
PHP provides a "magic" array called $_GET which already has the values parsed out for you.
For example:
one=1&two=2&three=3
Would result in this array:
Array ( [one] => 1 [two] => 2 [three] => 3 )
So you could access the variables like so:
$oneValue = $_GET['one']; // answer is 1
$twoValue = $_GET['two']; // and so on
If you provide array indexes, which your example does, it'll sort those out for you as well. So, to use your example above $_GET would look like:
Array
(
[ident] => Array
(
[0] => <IDENT_0>
[N] => <IDENT_N>
)
[value] => Array
(
[0] => <VALUE_0>
[N] => <VALUE_N>
)
[version] => Array
(
[0] => <VERSION_0>
[N] => <VERSION_N>
)
)
I'd assume your N keys will actually be numbers, so you'll be able to look them up like so:
$_GET['ident'][0] // => <IDENT_0>
$_GET['value'][0] // => <VALUE_0>
$_GET['version'][0] // => <VERSION_0>
You could loop across them all or whatever, and you will never have to worry about splitting them all out yourself.
Hope it helps you.
You can use preg_split with this pattern: &(?=ident)
$result = preg_split('~&(?=ident)~', $yourstring);
regex detail: &(?=ident) means & followed by ident
(?=..) is a lookahead assertion that performs only a check but match nothing.
Or using preg_match_all:
preg_match_all('~(?<=^|&)[^&]+&[^&]+&[^&]+(?=&|$)~', $yourstring, &matches);
$result = $matches[0];
pattern detail: (?<=..) is a lookbehind assertion
(?<=^|&) means preceded by the begining of the string ^ or an ampersand.
[^&]+ means all characters except the ampersand one or more times.
(?=&|$) means followed by an ampersand or the end of the string $.
Or you can use explode, and then a for loop:
$items = explode('&', $yourstring);
for ( $i=0; $i<sizeof($items); $i += 3 ) {
$result[] = implode('&', array_slice($items, $i, 3));
}

Split a single string into an array using specific Regex rules

I'm processing a single string which contains many pairs of data. Each pair is separated by a ; sign. Each pair contains a number and a string, separated by an = sign.
I thought it would be easy to process, but i've found that the string half of the pair can contain the = and ; sign, making simple splitting unreliable.
Here is an example of a problematic string:
123=one; two;45=three=four;6=five;
For this to be processed correctly I need to split it up into an array that looks like this:
'123', 'one; two'
'45', 'three=four'
'6', 'five'
I'm at a bit of dead end so any help is appreciated.
UPDATE:
Thanks to everyone for the help, this is where I am so far:
$input = '123=east; 456=west';
// split matches into array
preg_match_all('~(\d+)=(.*?);(?=\s*(?:\d|$))~', $input, $matches);
$newArray = array();
// extract the relevant data
for ($i = 0; $i < count($matches[2]); $i++) {
$type = $matches[2][$i];
$price = $matches[1][$i];
// add each key-value pair to the new array
$newArray[$i] = array(
'type' => "$type",
'price' => "$price"
);
}
Which outputs
Array
(
[0] => Array
(
[type] => east
[price] => 123
)
)
The second item is missing as it doesn't have a semicolon on the end, i'm not sure how to fix that.
I've now realised that the numeric part of the pair sometimes contains a decimal point, and that the last string pair does not have a semicolon after it. Any hints would be appreciated as i'm not having much luck.
Here is the updated string taking into account the things I missed in my initial question (sorry):
12.30=one; two;45=three=four;600.00=five
You need a look-ahead assertion for this; the look-ahead matches if a ; is followed by a digit or the end of your string:
$s = '12.30=one; two;45=three=four;600.00=five';
preg_match_all('/(\d+(?:.\d+)?)=(.+?)(?=(;\d|$))/', $s, $matches);
print_r(array_combine($matches[1], $matches[2]));
Output:
Array
(
[12.30] => one; two
[45] => three=four
[600.00] => five
)
I think this is the regex you want:
\s*(\d+)\s*=(.*?);(?=\s*(?:\d|$))
The trick is to consider only the semicolon that's followed by a digit as the end of a match. That's what the lookahead at the end is for.
You can see a detailed visualization on www.debuggex.com.
You can use following preg_match_all code to capture that:
$str = '123=one; two;45=three=four;6=five;';
if (preg_match_all('~(\d+)=(.+?);(?=\d|$)~', $str, $arr))
print_r($arr);
Live Demo: http://ideone.com/MG3BaO
$str = '123=one; two;45=three=four;6=five;';
preg_match_all('/(\d+)=([a-zA-z ;=]+)/', $str,$matches);
echo '<pre>';
print_r($matches);
echo '</pre>';
o/p:
Array
(
[0] => Array
(
[0] => 123=one; two;
[1] => 45=three=four;
[2] => 6=five;
)
[1] => Array
(
[0] => 123
[1] => 45
[2] => 6
)
[2] => Array
(
[0] => one; two;
[1] => three=four;
[2] => five;
)
)
then y can combine
echo '<pre>';
print_r(array_combine($matches[1],$matches[2]));
echo '</pre>';
o/p:
Array
(
[123] => one; two;
[45] => three=four;
[6] => five;
)
Try this but this code is written in c#, you can change it into php
string[] res = Regex.Split("123=one; two;45=three=four;6=five;", #";(?=\d)");
--SJ

What is the most efficient way to swap the values from 2 arrays matching a replacement key in PHP?

The first array defines the current values:
Array ( [0] => schools [1] => high-wood [2] => students )
The second array is a map that is triggered by the first array and also hold the replacement keys:
Array ( [/schools/{school-name}/students/] => /{school-name}/students/ )
The idea is that the second segment of the array key holds the replacement key and the final returned array is the output map indicating the place of the replacement key.
The final desired output would then be:
/high-wood/students/
I am trying to find a generic solution to this that may have any number of incoming values, and any number of replacement keys in any position.
Here is an example of the generic incoming array:
Array ( [0] => param1 [1] => param2 [2] => key-value )
And the generic-ish map:
Array ( [/param1/param2/{key-map}/] => /{map-key}/anything/ )
The output of this would be:
/key-value/anything/
The basic idea is that the map-key is detected at the second segment (it could be anywhere), so that value is taken from the incoming array and put into the map-key holder of the output array.
Currently I have managed to make a vomitus array of foreach loops and preg_matches and I fear even presenting those would further confuse the issue.
Hmm...how about something like this. Untested:
$input = array('schools', 'high-wood', 'students');
// Here I'm making the blithe assumption that you can further tweak the URI map
$uriMap = array('^/schools/([^/]+)/students/$' => '/{school-name}/students/');
// ^ ^^^^^^^ ^
// anchor capturing group anchor
// Massage input to match format of $uriMap
$inUri = '/'.implode('/', $input).'/';
foreach($uriMap as $pattern => $target){
if(false !== preg_match($pattern, $inUri, $matches){
// $matches[1] should have the matched string
$mapped = str_replace('{school-name}', $matches[1], $target);
break;
}
}
echo $mapped;
/high-wood/students/
Cheers

trying to filter string with <br> tags using explode, does not work

I get a string that looks like this
<br>
ACCEPT:YES
<br>
SMMD:tv240245ce
<br>
is contained in a variable $_session['result']
I am trying to parse through this string and get the following either in an array or as separate variables
ACCEPT:YES
tv240245ce
I first tried
to explode the string using as the delimiter, and that did not work
then I already tried
$yes = explode(":", strip_tags($_SESSION['result']));
echo print_r($yes);
which gives me an array like so
Array ( [0] => ACCEPT [1] => YESSEED [2] => tv240245ce ) 1
which gives me one of my answers.
Please what would be a great way of trying to achieve what I am trying to achieve?
is there a way to get rid of the first and last?
then use the remaining one as a delimiter to explode the string ?
or what's the best way to go about this ?
This will do it:
$data=preg_split('/\s?<br>\s?/', str_replace('SMMD:','',$data), NULL, PREG_SPLIT_NO_EMPTY);
See example here:
CodePad
You can also skip caring about the spurious <br> and treat the whole string as key:value format with a simple regex like:
preg_match_all('/^(\w+):(.*)/', $text, $result, PREG_SET_ORDER);
This requires that you really have line breaks in it though. Gives you a $result list which is easy to convert into an associative array afterwards:
[0] => Array
(
[0] => ACCEPT:YES
[1] => ACCEPT
[2] => YES
)
[1] => Array
(
[0] => SMMD:tv240245ce
[1] => SMMD
[2] => tv240245ce
)
First, do a str_replace to remove all instances of "SMMD:". Then, Explode on "< b r >\n". Sorry for weird spaced, it was encoding the line break.
Include the new line character and you should get the array you want:
$mystr = str_replace( 'SMMD:', '', $mystr );
$res_array = explode( "<br>\n", $mystr );

Categories