Imagine I have a certain text file like this:-
52 apple, one and teen, 682
How to do I take them like this?
$a['aa']['a1'] - 52
$a['aa']['a2'] - apple
$a['bb']['b1'] - one
$a['bb']['b2'] - and
$a['bb']['b3'] - teen
$a['cc']['c1'] - 682
This reads lines from a file, splits them by comma+space and splits each of those by a space:
<?php
$lines = file($filename);
$foo = array_map(
function($v) {
return array_map(
function($u) {
return explode(" ", $u);
},
explode(", ", trim($v))
);
},
$lines
);
var_dump($foo);
Result:
array(1) {
[0]=>
array(3) {
[0]=>
array(2) {
[0]=>
string(2) "52"
[1]=>
string(5) "apple"
}
[1]=>
array(3) {
[0]=>
string(3) "one"
[1]=>
string(3) "and"
[2]=>
string(4) "teen"
}
[2]=>
array(1) {
[0]=>
string(3) "682"
}
}
}
If you really need specific indices you could handle those in the anonymous functions for each array_map on your own. Right now they're just numerically indexed.
Related
I have the next array with data (which is dynamically generated).
Now I want to do some Magic and tweak the array.
array(1) {
["table"]=>
array(3) {
["header"]=>
array(4) {
[0]=>
array(1) {
["c"]=>
string(4) "Naam"
}
[1]=>
array(1) {
["c"]=>
string(7) "Functie"
}
[2]=>
array(1) {
["c"]=>
string(13) "Nevenfuncties"
}
[3]=>
array(1) {
["c"]=>
string(34) " commissies"
}
}
["caption"]=>
bool(false)
["body"]=>
array(3) {
[0]=>
array(4) {
[0]=>
array(1) {
["c"]=>
string(16) "*|class:orange|*"
}
[1]=>
array(1) {
["c"]=>
string(6) "dsasad"
}
[2]=>
array(1) {
["c"]=>
string(0) ""
}
[3]=>
array(1) {
["c"]=>
string(0) ""
}
}
[1]=>
array(4) {
[0]=>
array(1) {
["c"]=>
string(4) "brrr"
}
[1]=>
array(1) {
["c"]=>
string(6) "adsdsa"
}
[2]=>
array(1) {
["c"]=>
string(0) ""
}
[3]=>
array(1) {
["c"]=>
string(0) ""
}
}
[2]=>
array(4) {
[0]=>
array(1) {
["c"]=>
string(6) "dsasad"
}
[1]=>
array(1) {
["c"]=>
string(6) "dsadas"
}
[2]=>
array(1) {
["c"]=>
string(4) "dsad"
}
[3]=>
array(1) {
["c"]=>
string(0) ""
}
}
}
}
}
When we look at the ['header'] it contains ['c'] (the cell data). This can be text, but also a tag.
For example: *|class:orange|* here some text.
Now I want to split those up and overwrite the ['c'] if it contains '|class:orange|'.
So when you have this:
array(1) {
["c"]=>
string(7) "*|class:orange|* hello"
}
It would become this:
array(2) {
["c"]=>
string(7) "hello",
["class"]=>
string(7) "orange",
}
This way I could split the class and add it to the array. But I am stuck at the preg_match.
foreach ($table as &$row) {
foreach ($row['header'] as &$header) {
// $header['class'] = 123;
preg_match('/\*\|class:([^\|])\|\*/', $header['c'], $matches);
}
}
I need to do 2 things
Add an attribute to the array ($header['class']) with the class after class:example.
I need to replace the $header['c'] so it does not contain *|class:orange|* and only the rest of the text.
No need for regexp (yet). Tags can be found with delimiter positioning:
foreach ($row['header'] as &$header) {
$str = $header['c'];
$tagged = substr($str, 0, 2) === '*|' && $pos = strpos($str, '|* ');
if (!$tagged) { continue; }
[$tag, $value] = explode(':', substr($str, 2, $pos - 2));
$header['c'] = substr($str, $pos + 3);
$header[$tag] = $value;
}
You could for example use 2 capturing groups and use those as the values for the c and new class key.
For the second capturing group you could make sure to match at least a single non whitespace char using \S
Note to repeat the character class 1 or more times and you don't have to escape the pipe in the character class.
\*\|class:([^|]+)\|\*\h*(\S.*)
Or if what follows for group 2 can be optional:
\*\|class:([^\|]+)\|\*\h*(.*)
Regex demo
Explanation first pattern
\*\| Match *|
class: Match literally
([^|]+) Capture group 1, match 1+ times any char except |
\|\*\h* Match |* followed by 0+ horizontal whitespace chars
(\S.*) Capture group 2, match a non whitespace char and 0+ times any char except a newline
Regex demo | Php demo
Example code
$array = [
"c" => "*|class:orange|* hello"
];
$pattern = "~\*\|class:([^|]+)\|\*\h*(\S.*)~";
foreach ($array as $key => $string) {
if (preg_match($pattern, $string, $matches)) {
$array[$key] = $matches[2];
$array["class"] = $matches[1];
}
}
print_r($array);
Output
Array
(
[c] => hello
[class] => orange
)
I'm trying to convert a string into a multidimentional array.
I've found many answers online but they expect you to have array keys etc...
My String:
UserIds\n234234\n20053\n19928\n16325
I've tried the usual way:
$arr= array();
$arr = explode("\n", $string);
and i've also tried
$arr[] = explode("\n", $string);
but the result is always like this:
array(5) {
[0]=> string(7) "UserIds"
[1]=> string(6) "234234"
[2]=> string(5) "20053"
[3]=> string(5) "19928"
[4]=> string(5) "16325"
}
My Expected Result:
array(5) {
[0]=> array(1) { [0]=> string(7) "UserIds" }
[1]=> array(1) { [0]=> int(234234) }
[2]=> array(1) { [0]=> int(20053) }
[3]=> array(1) { [0]=> int(19928) }
[4]=> array(1) { [0]=> int(16325) }
}
One way to do it could be to map the response using array_map and wrap the items in an array:
$string = "UserIds\n234234\n20053\n19928\n16325";
$arr = array_map(function($x){return [$x];}, explode("\n", $string));
print_r($arr);
Demo
I am aware of this question, but I have an additional one to search for an array-key. Take a look at this:
array(2) {
[0]=>
array(2) {
["name"]=>
string(6) "Text 1"
["types"]=>
array(3) {
[0]=>
string(7) "Level 1"
[1]=>
string(14) "something else"
[2]=>
string(15) "whatisearchfor1"
}
}
[1]=>
array(2) {
["name"]=>
string(6) "Text 2"
["types"]=>
array(3) {
[0]=>
string(7) "Level 2"
[1]=>
string(14) "something else"
[2]=>
string(15) "whatisearchfor2"
}
}
}
This snippet...
echo array_search("Text 2", array_column($response, "name"));
...gives me a 1 for the second array-key, in which the term was found.
But how do I receive the global array-key (0 or 1), if I search for whatisearchfor2, which is stored in the multi-array "types"?
echo array_search("whatisearchfor2", array_column($response, "types"));
...doesn't work.
In your case array_column($response, "types") will return an array of arrays. But to get "global array-key (0 or 1), if you search for whatisearchfor2" use the following approach with array_walk:
$key = null; // will contain the needed 'global array-key' if a search was successful
$needle = "whatisearchfor2"; // searched word
// assuming that $arr is your initial array
array_walk($arr, function ($v,$k) use(&$key, $needle){
if (in_array($needle, $v['types'])){
$key = $k;
}
});
var_dump($key); // outputs: int(1)
Kinda of a noobie in PHP and Regex, I receive the following from a web service:
test:002005#1111#333333#;10205#2000#666666#;002005#1111#55555#;
The above line is a sequence of 3 numbers which repeats 3 times. I would like to get the 3rd number of each sequence and I believe the best course (besides 3000 explodes) would be preg_match_all but I am having a tough time wrapping my mind around RegEx.
The end result should look like this:
Array
(
[0] => 333333
[1] => 666666
[2] => 55555
)
Thanks in advance for any help.
if(preg_match_all('/.*?(?:\d+#){2}(\d+)#;/',$s,$m)) {
print_r($m[1]);
}
http://ideone.com/99M9t
or
You can do it using explode as:
$input = rtrim($input,';');
$temp1 = explode(';',$input);
foreach($temp1 as $val1) {
$temp2 = explode('#',$val1);
$result[] = $temp2[2];
}
print_r($result);
http://ideone.com/VH29g
Use the function explode()
<?php
$pizza = "piece1#piece2#piece3#piece4#piece5#piece6";
$pieces = explode("#", $pizza);
echo $pieces[0]; // piece1
echo $pieces[1]; // piece2
?>
I don't remember exactly how the saying goes but...
"You have a problem and decide to use regular expressions... now you have two problems."
Your problem can easily be solved if we assume 'test:' isn't part of the actual string to be parsed.
<?php
$in = '002005#1111#333333#;10205#2000#666666#;002005#1111#55555#;';
function splitGroupsAndGetColumn($input, $groupSeparator, $columnSeparator, $columnIndex, $skipEmpty=true)
{
$result = array();
$groups = explode($groupSeparator, $input);
foreach($groups as $group)
{
$columns = explode($columnSeparator, $group);
if (isset($columns[$columnIndex]))
{
array_push($result, $columns[$columnIndex]);
}
else if (! $skipEmpty)
{
array_push($result, NULL);
}
}
return $result;
}
var_dump(splitGroupsAndGetColumn($in, ';', '#', 2));
Output:
array(3) {
[0]=>
string(6) "333333"
[1]=>
string(6) "666666"
[2]=>
string(5) "55555"
}
You could use preg_match_all for this task, which makes the task quite simple:
$a = "test:002005#1111#333333#;10205#2000#666666#;002005#1111#55555#;";
preg_match_all('/#(\d+)#;/', $a, $m);
print_r($m);
$m[1] contains the output, you want.
Reference: http://php.net/manual/en/function.preg-match-all.php
My version :)
The regex (\d+) means I want all that is a number one or more
php > $a = '002005#1111#333333#;10205#2000#666666#;002005#1111#55555#';
php > preg_match_all('/(\d+)/',$a,$matches);
php > var_dump($matches);
array(2) {
[0]=>
array(9) {
[0]=>
string(6) "002005"
[1]=>
string(4) "1111"
[2]=>
string(6) "333333"
[3]=>
string(5) "10205"
[4]=>
string(4) "2000"
[5]=>
string(6) "666666"
[6]=>
string(6) "002005"
[7]=>
string(4) "1111"
[8]=>
string(5) "55555"
}
[1]=>
array(9) {
[0]=>
string(6) "002005"
[1]=>
string(4) "1111"
[2]=>
string(6) "333333"
[3]=>
string(5) "10205"
[4]=>
string(4) "2000"
[5]=>
string(6) "666666"
[6]=>
string(6) "002005"
[7]=>
string(4) "1111"
[8]=>
string(5) "55555"
}
}
Given:
$val = "font-size:12px;color:#ff0000;font-family:Arial";
The following code will explode the string twice, to produce an array of arrays:
$val = explode(';',$val);
foreach($val as &$v)
$v = explode(':',$v);
var_dump($val);
The output is:
array(3) {
[0]=>
array(2) {
[0]=>
string(9) "font-size"
[1]=>
string(4) "12px"
}
[1]=>
array(2) {
[0]=>
string(4) "fill"
[1]=>
string(7) "#ff0000"
}
[2]=>
&array(2) {
[0]=>
string(11) "font-family"
[1]=>
string(5) "Arial"
}
}
Is there a more efficient / cleaner way to achieve the same result?
I'd prefer something with no lambda functions since PHP 5.2 doesn't support them. But this is a purely intellectual question anyway, so, that's just a preference.
You can try with:
$input = "font-size:12px;color:#ff0000;font-family:Arial";
preg_match_all('/([^:]*?):([^;]*);?/', $input, $matches);
$output = array_combine($matches[1], $matches[2]);
Output:
array(3) {
["font-size"]=>
string(4) "12px"
["color"]=>
string(7) "#ff0000"
["font-family"]=>
string(5) "Arial"
}
I'd recommend against references--you can run into some odd errors. But your approach is fine. Alternatively, you could do something with array_map:
$val = array_map(function($v) { return explode(':', $v); }, explode(';', $val)));