I have a pretty large array that I would need to parse, but the request changes depending on enabled/disabled parameters.
For example:
$array['a'][1]['b'][1]['c'][1] = 'asd';
$str = $array['a'][1];
dd($str);
This would give me:
Array
(
[b] => Array
(
[1] => Array
(
[c] => Array
(
[1] => asd
)
)
)
)
Which, of course, is correct. But now, if I know, that I need also the next parameter, I would need to add that like $str = $array['a'][1]['b'];.
But since there are way too many combinations, I wondered, if I can construct the call manually, something like this":
$str = $array['a'][1];
if ($b) {
$str .= ['b'][1];
}
if ($c) {
$str .= ['c'][1];
}
dd($str);
Any hints will be appreciated.
PS: I know I can do this with eval, but was really looking for a better solution:
eval("\$str = \$array$str;");
dd($str);
It can be done with Reference
$string = "['a'][1]['b'][1]";
// Maybe, not optimal, but it's not the point of the code
preg_match_all('/\[\'?([^\]\']+)\'?\]/', $string, $steps);
// "Root" of the array
$p = &$array;
foreach($steps[1] as $s) {
// Next step with current key
if (isset($p[$s]) && is_array($p)) $p = &$p[$s];
else throw new Exception("No such item");
}
// Target value
$str = $p;
demo
Related
This may be able to be accomplished with a regular expression but I have no idea. What I am trying to accomplish is being able to parse a string with a given delimiter but when it sees a set of brackets it parses differently. As I am a visual learning let me show you an example of what I am attempting to achieve. (PS this is getting parsed from a url)
Given the string input:
String1,String2(data1,data2,data3),String3,String4
How can I "transform" this string into this array:
{
"String1": "String1",
"String2": [
"data1",
"data2",
"data3"
],
"String3": "String3",
"String4": "String4
}
Formatting doesn't have to be this strict as I'm just attempting to make a simple API for my project.
Obviously things like
array explode ( string $delimiter , string $string [, int $limit = PHP_INT_MAX ] )
Wouldn't work because there are commas inside the brackets as well. I've attempted manual parsing looking at each character at a time but I fear for the performance and it doesn't actually work anyway. I've pasted the gist of my attempt.
https://gist.github.com/Fudge0952/24cb4e6a4ec288a4c492
While you could try to split your initial string on commas and ignore anything in parentheses for the first split, this necessarily makes assumptions about what those string values can actually be (possibly requiring escaping/unescaping values depending on what those strings have to contain).
If you have control over the data format, though, it would be far better to just start with JSON. It's well-defined and well-supported.
You can either build an ad-hoc parser like (mostly untested):
<?php
$p = '!
[^,\(\)]+ # token: String
|, # token: comma
|\( # token: open
|\) # token: close
!x';
$input = 'String1,String2(data1,data2,data3,data4(a,b,c)),String3,String4';
preg_match_all($p, $input, $m);
// using a norewinditerator, so we can use nested foreach-loops on the same iterator
$it = new NoRewindIterator(
new ArrayIterator($m[0])
);
var_export( foo( $it ) );
function foo($tokens, $level=0) {
$result = [];
$current = null;
foreach( $tokens as $t ) {
switch($t) {
case ')':
break; // foreach loop
case '(':
if ( is_null($current) ) {
throw new Exception('moo');
}
$tokens->next();
$result[$current] = foo($tokens, $level+1);
$current = null;
break;
case ',':
if ( !is_null($current) ) {
$result[] = $current;
$current = null;
}
break;
default:
$current = $t;
break;
}
}
if ( !is_null($current) ) {
$result[] = $current;
}
return $result;
}
prints
array (
0 => 'String1',
'String2' =>
array (
0 => 'data1',
1 => 'data2',
2 => 'data3',
'data4' =>
array (
0 => 'a',
1 => 'b',
2 => 'c',
),
),
1 => 'String3',
2 => 'String4',
)
(but will most certainly fail horribly for not-well-formed strings)
or take a look at lexer/parser generator like e.g. PHP_LexerGenerator and PHP_ParserGenerator.
This is a solution with preg_match_all():
$string = 'String1,String2(data1,data2,data3),String3,String4,String5(data4,data5,data6)';
$pattern = '/([^,(]+)(\(([^)]+)\))?/';
preg_match_all( $pattern, $string, $matches );
$result = array();
foreach( $matches[1] as $key => $val )
{
if( $matches[3][$key] )
{ $add = explode( ',', $matches[3][$key] ); }
else
{ $add = $val; }
$result[$val] = $add;
}
$json = json_encode( $result );
3v4l.org demo
Pattern explanation:
([^,(]+) group 1: any chars except ‘,’ and ‘(’
(\(([^)]+)\))? group 2: zero or one occurrence of brackets wrapping:
└──┬──┘
┌──┴──┐
([^)]+) group 3: any chars except ‘,’
Is there a way of turning this:
network={
ssid="tele2-ssid-66577"
#psk="testtest2"
psk=8308d8e34c60fe471fda6837ab5821694e8cf51a655f24295797df33d02df6e9
}
into an object or an array with php?
I tried json_decode with no result.
------------- UPDATE:
the end goal is to extract only the psk key, I just thought turning it into an object/array would be the easiest thing to do rather than meddling with regular expressions or fiddling with the string, but maybe it's not possible...
I ran it through regex and then some processing
$str = 'network={
ssid="tele2-ssid-66577"
#psk="testtest2"
psk=8308d8e34c60fe471fda6837ab5821694e8cf51a655f24295797df33d02df6e9
}';
$output = array();
if (preg_match_all('/(([^=]+)=\{|\s+([^#]+)=(.*))/', $str, $match) and sizeof($match[2]) > 2) {
$output[$match[2][0]] = array();
for ($i=1; $i<sizeof($match[2]); $i++) {
$key = trim($match[3][$i]);
$value = trim($match[4][$i]);
// remove outer double quotes
if (preg_match('/^"(.*)"$/', $value, $match2)) $value = $match2[1];
// save
$output[$match[2][0]][$key] = $value;
}
}
print_r($output);
Giving the output:
Array
(
[network] => Array
(
[ssid] => tele2-ssid-66577
[psk] => 8308d8e34c60fe471fda6837ab5821694e8cf51a655f24295797df33d02df6e9
)
)
I need to get all the positions of a character in a string in a form of an array. I know about the php function strpos() but it does not accept an array as an argument.
This is required:
$name = "australia"; //string that needs to be searched
$positions_to_find_for = "a"; // Find all positions of character "a" in an array
$positions_array = [0,5,8]; // This should be the output that says character "a" comes at positions 0, 5 and 8 in string "australia"
Question: What Loops can help me build a function that can help me achieve the required output?
You can use a for to loop that string:
$name = "australia";
$container = array();
$search = 'a';
for($i=0; $i<strlen($name); $i++){
if($name[$i] == $search) $container[] = $i;
}
print_r($container);
/*
Array
(
[0] => 0
[1] => 5
[2] => 8
)
*/
Codepad Example
No loops necessary
$str = 'australia';
$letter='a';
$letterPositions = array_keys(
array_intersect(
str_split($str),
array($letter)
)
);
var_dump($letterPositions);
I have the following code but I'm not a big fan of reg exp as they are too confusing:
<?php
$r = '|\\*(.+)\\*|';
$w = '';
$s = 'hello world *copyMe* here';
function callbk($str){
print_r($str);
foreach($str as $k=>$v) {
echo $v;
}
}
$t = preg_replace_callback($r,'callbk',$s);
//output: Array ( [0] => *copyMe* [1] => copyMe ) *copyMe*copyMe
?>
my question is why is there both "*copyMe*" and "copyMe"?
i was hoping to get either one or the other, not both.
any help would be appriciated.
Because you are using a capturing expression (). If you omit the brackets you will only get *copyMe*.
So here is the string that im scraping a page to read (using file get contents)
<th>Kills (K)</th><td><strong>4,751</strong></td><td><strong>0</strong></td>
How can i navigate to the above section of the page contents, and then isolate the 4,751 inside the above html and load it into $kills ?
Difficulty: the number will change and have additional numbers before the comma
Ok got it to work by removing all spaces and turning the page contents into a string
<?
$url = "http://combatarms.nexon.net/Community/Profile.aspx?user=tect0n";
$raw = file_get_contents($url);
$newlines = array("\t","\n","\r","\x20\x20","\0","\x0B");
$content = str_replace($newlines, "", html_entity_decode($raw));
preg_match_all('|<th>.*?</th><td><strong>(\d+,\d+)</strong></td>|', $content,$match);
?>
This returns
Array ( [0] => Array ( [0] => Kills (K)4,751 [1] => Deaths (D)4,868 ) [1] => Array ( [0] => 4,751 [1] => 4,868 ) )
This should do it:
if (preg_match("/<th>Kills \(K\)<\/th><td><strong>([\d,]+)<\/strong>/",
$string, $matches)) {
$kills = str_replace(",","",$matches[1]);
} else {
$kills = 0;
}
This is what im using and gnarf's code returns 0
RageZ's returned an empty array
<?
$string = file_get_contents("http://combatarms.nexon.net/Community/Profile.aspx?user=tect0n");
if (preg_match("/<th>Kills \(K\)<\/th><td><strong>([\d,]+)<\/strong>/",
$string, $matches)) {
$kills = str_replace(",","",$matches[1]);
} else {
$kills = 0;
}
echo $kills;
?>
Coming up 0
here you go
preg_match_all('|<th>.*?</th><td><strong>([\d,]+)</strong></td>|x', $subject,$match);
var_dump($match);
but if I were you I would use xpath it's is safer.
preg_match_all('#\(K\).*?<strong>(.*?)</strong>#s',$html,$matches);
tell me that aint pretty
preg_match('#<table class="tbl_profile">(.*?)</table>#s',file_get_contents('http://combatarms.nexon.net/Community/Profile.aspx?user=tect0n'),$m);
preg_match_all('#<tr>.*?<t.*?>(.*?)</t.*?>.*?<t.*?>(.*?)</t.*?>.*?<t.*?>(.*?)</t.*?>.*?</tr>#s',preg_replace('#(<strong>)|(</strong>)|(<!--.*?-->)#s','',$m[1]),$r);
echo 'You got '.$r[2][1].' killz';
//print_r($r);
now tell me thaaaaaaat aint pretty, cooooool it.