Im making a property parser, and I want it to be able to parse a string of any length.
For example, I would like to be able to do the following call:
getDynamicProp("cheese:no;sauce:yes;chicken:brown", "sauce");
and have "yes" returned from it.
Here is what I've got so far:
function getDynamicProp($string , $property){
$args = func_num_args();
$args_val = func_get_args();
$strlen = mb_strlen($string);
$propstrstart = mb_strpos($string , $property . ":");
$propstrend1 = substr($string , $propstrstart , )
$propstrend = mb_strpos($string , ";" , $propstrstart);
$finalvalue = substr($string , $propstrstart , $propstrend);
$val = str_replace($property . ":" , "" , $finalvalue);
$val2 = str_replace(";" , "" , $val);
return $val2;
}
You can try this. The function uses explode to transform strings into arrays, which are more easily manipulable :
function getDynamicProp($string , $property){
$the_result = array();
$the_array = explode(";", $string);
foreach ($the_array as $prop) {
$the_prop = explode(":", $prop);
$the_result[$the_prop[0]] = $the_prop[1];
}
return $the_result[$property];
}
$the_string = "cheese:no;sauce:yes;chicken:brown";
echo getDynamicProp($the_string,"cheese");
echo getDynamicProp($the_string,"sauce");
echo getDynamicProp($the_string,"chicken");
I think you make it over-complicated, or I didn't understand what you want.
I will go with regex instead of making position search.
Here is what I'll use:
function getDynamicProp($string , $property){
if (preg_match('/(^|;)' . $property . ':(?P<value>[^;]+)/', $string, $matches)) {
return $matches['value'];
}
return false;
}
Check here to visualize regex
You would be better off using json_encode and json_decode if you are in control of this string. If not it's much easier like this:
function getDynamicProp($string, $property) {
$string = str_replace(array(':',';'), array('=','&'), $string);
parse_str($string, $result);
return $result[$property];
}
Or store them as cheese=no&sauce=yes&chicken=brown. Then it's even easier still.
Related
I have the following text string: "Gardening,Landscaping,Football,3D Modelling"
I need PHP to pick out the string before the phrase, "Football".
So, no matter the size of the array, the code will always scan for the phrase 'Football' and retrieve the text immediately before it.
Here is my (lame) attempt so far:
$array = "Swimming,Astronomy,Gardening,Rugby,Landscaping,Football,3D Modelling";
$find = "Football";
$string = magicFunction($find, $array);
echo $string; // $string would = 'Landscaping'
Any help with this would be greatly appreciated.
Many thanks
$terms = explode(',', $array);
$index = array_search('Football', $terms);
$indexBefore = $index - 1;
if (!isset($terms[$indexBefore])) {
trigger_error('No element BEFORE');
} else {
echo $terms[$indexBefore];
}
//PHP 5.4
echo explode(',Football', $array)[0]
//PHP 5.3-
list($string) = explode(',Football', $array);
echo $string;
$array = array("Swimming","Astronomy","Gardening","Rugby","Landscaping","Football","3D" "Modelling");
$find = "Football";
$string = getFromOffset($find, $array);
echo $string; // $string would = 'Landscaping'
function getFromOffset($find, $array, $offset = -1)
{
$id = array_search($find, $array);
if (!$id)
return $find.' not found';
if (isset($array[$id + $offset]))
return $array[$id + $offset];
return $find.' is first in array';
}
You can also set the offset to be different from 1 previous.
function test()
{
$content = "lang=en]text en|lang=sp]text sp";
$atts = explode('|', $content);
}
What I'm trying to do is to allow myself to echo $param[en] to get "text en", $param[sp] to get "text sp". Is that possible?
the $content is actually from a database record.
$param = array();
$langs = explode('|', $content);
foreach ($langs as $lang) {
$arr = explode(']', $lang);
$key = substr($arr[0], 5);
$param[$key] = $arr[1];
}
This is if you are sure $content is well-formatted. Otherwise you will need to put in additional checks to make sure $langs and $arr are what they should be. Use the following to quickly check what's inside an array:
echo '<pre>'.print_r($array_to_be_inspected, true).'</pre>';
Hope this helps
if this is not hard coded string in $content
function test()
{
$content = "lang=en]text en|lang=sp]text sp";
$atts = explode('|', $content);
foreach($atts as $att){
$tempLang = explode("]", $att);
$params[array_pop(explode("=", $tempLang[0]))] = $tempLang[1];
}
var_dump($params);
}
I think in this case you could use regular expressions.
$atts = explode('|', $content);
foreach ($atts as $subtext) {
if (preg_match('/lang=(\w+)\](\w+) /', $subtext, $regs)) {
$param[$regs[0]] = $regs[1];
}
}
Although it seems that you have a bad database structure if that value comes from a database - if you can edit it, try to make the database adhere to make the database normal.
I am using an api to retrieve data from another server the data returned is something like this:
accountid=10110 type=prem servertime=1263752255 validuntil=1266163393
username= curfiles=11 curspace=188374868 bodkb=5000000 premkbleft=24875313
This is a whole string I need two values out of whole string, I am currently using preg_match to get it, but just to learn more and improve my coding is there any other way or function in which all values are automatically convert to array?
Thank You.
Sooo, my faster-than-preg_split, strpos-based function looks like this:
function unpack_server_data($serverData)
{
$output = array();
$keyStart = 0;
$keepParsing = true;
do
{
$keyEnd = strpos($serverData, '=', $keyStart);
$valueStart = $keyEnd + 1;
$valueEnd = strpos($serverData, ' ', $valueStart);
if($valueEnd === false)
{
$valueEnd = strlen($serverData);
$keepParsing = false;
}
$key = substr($serverData, $keyStart, $keyEnd - $keyStart);
$value = substr($serverData, $valueStart, $valueEnd - $valueStart);
$output[$key] = $value;
$keyStart = $valueEnd + 1;
}
while($keepParsing);
return $output;
}
It looks for an equals character, then looks for a space character, and uses these two to decide where a key name begins, and when a value name begins.
Using explode is the fastest for this, no matter what.
However, to answer you question, you can do this many ways. But just because you can, doesn't mean you should. But if you really wanna make it weird, try this.
UPdated using strpos
$arr = array();
$begin = 0;
$str = trim($str); # remove leading and trailing whitespace
while ($end = strpos($str, ' ', $begin)) {
$split = strpos($str, '=', $begin);
if ($split > $end) break;
$arr[substr($str, $begin, $split-$begin)] = substr($str, $split+1, $end-$split-1);
$begin = $end+1;
}
try out parse_str maybe you need to do str_replace(' ', '&', $string); before
I'm pulling a JSON feed that is invalid JSON. It's missing quotes entirely. I've tried a few things, like explode() and str_replace(), to get the string looking a little bit more like valid JSON, but with an associate JSON string inside, it generally gets screwed up.
Here's an example:
id:43015,name:'John Doe',level:15,systems:[{t:6,glr:1242,n:'server',s:185,c:9}],classs:0,subclass:5
Are there any JSON parsers for php out there that can handle invalid JSON like this?
Edit: I'm trying to use json_decode() on this string. It returns nothing.
All the quotes should be double quotes " and not single quotes '.
All the keys should be quoted.
The whole element should be an object.
function my_json_decode($s) {
$s = str_replace(
array('"', "'"),
array('\"', '"'),
$s
);
$s = preg_replace('/(\w+):/i', '"\1":', $s);
return json_decode(sprintf('{%s}', $s));
}
This regex will do the trick
$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);
From my experience Marko's answer doesnt work anymore. For newer php versions use this istead:
$a = "{id:43015,name:'John Doe',level:15,systems:[{t:6,glr:1242,n:'server',s:185,c:988}],classs:0,subclass:5}";
$a = preg_replace('/(,|\{)[ \t\n]*(\w+)[ ]*:[ ]*/','$1"$2":',$a);
$a = preg_replace('/":\'?([^\[\]\{\}]*?)\'?[ \n\t]*(,"|\}$|\]$|\}\]|\]\}|\}|\])/','":"$1"$2',$a);
print_r($a);
I know this question is old, but I hope this helps someone.
I had a similar problem, in that I wanted to accept JSON as a user input, but didn't want to require tedious "quotes" around every key. Furthermore, I didn't want to require quotes around the values either, but still parse valid numbers.
The simplest way seemed to be writing a custom parser.
I came up with this, which parses to nested associative / indexed arrays:
function loose_json_decode($json) {
$rgxjson = '%((?:\{[^\{\}\[\]]*\})|(?:\[[^\{\}\[\]]*\]))%';
$rgxstr = '%("(?:[^"\\\\]*|\\\\\\\\|\\\\"|\\\\)*"|\'(?:[^\'\\\\]*|\\\\\\\\|\\\\\'|\\\\)*\')%';
$rgxnum = '%^\s*([+-]?(\d+(\.\d*)?|\d*\.\d+)(e[+-]?\d+)?|0x[0-9a-f]+)\s*$%i';
$rgxchr1 = '%^'.chr(1).'\\d+'.chr(1).'$%';
$rgxchr2 = '%^'.chr(2).'\\d+'.chr(2).'$%';
$chrs = array(chr(2),chr(1));
$escs = array(chr(2).chr(2),chr(2).chr(1));
$nodes = array();
$strings = array();
# escape use of chr(1)
$json = str_replace($chrs,$escs,$json);
# parse out existing strings
$pieces = preg_split($rgxstr,$json,-1,PREG_SPLIT_DELIM_CAPTURE);
for($i=1;$i<count($pieces);$i+=2) {
$strings []= str_replace($escs,$chrs,str_replace(array('\\\\','\\\'','\\"'),array('\\','\'','"'),substr($pieces[$i],1,-1)));
$pieces[$i] = chr(2) . (count($strings)-1) . chr(2);
}
$json = implode($pieces);
# parse json
while(1) {
$pieces = preg_split($rgxjson,$json,-1,PREG_SPLIT_DELIM_CAPTURE);
for($i=1;$i<count($pieces);$i+=2) {
$nodes []= $pieces[$i];
$pieces[$i] = chr(1) . (count($nodes)-1) . chr(1);
}
$json = implode($pieces);
if(!preg_match($rgxjson,$json)) break;
}
# build associative array
for($i=0,$l=count($nodes);$i<$l;$i++) {
$obj = explode(',',substr($nodes[$i],1,-1));
$arr = $nodes[$i][0] == '[';
if($arr) {
for($j=0;$j<count($obj);$j++) {
if(preg_match($rgxchr1,$obj[$j])) $obj[$j] = $nodes[+substr($obj[$j],1,-1)];
else if(preg_match($rgxchr2,$obj[$j])) $obj[$j] = $strings[+substr($obj[$j],1,-1)];
else if(preg_match($rgxnum,$obj[$j])) $obj[$j] = +trim($obj[$j]);
else $obj[$j] = trim(str_replace($escs,$chrs,$obj[$j]));
}
$nodes[$i] = $obj;
} else {
$data = array();
for($j=0;$j<count($obj);$j++) {
$kv = explode(':',$obj[$j],2);
if(preg_match($rgxchr1,$kv[0])) $kv[0] = $nodes[+substr($kv[0],1,-1)];
else if(preg_match($rgxchr2,$kv[0])) $kv[0] = $strings[+substr($kv[0],1,-1)];
else if(preg_match($rgxnum,$kv[0])) $kv[0] = +trim($kv[0]);
else $kv[0] = trim(str_replace($escs,$chrs,$kv[0]));
if(preg_match($rgxchr1,$kv[1])) $kv[1] = $nodes[+substr($kv[1],1,-1)];
else if(preg_match($rgxchr2,$kv[1])) $kv[1] = $strings[+substr($kv[1],1,-1)];
else if(preg_match($rgxnum,$kv[1])) $kv[1] = +trim($kv[1]);
else $kv[1] = trim(str_replace($escs,$chrs,$kv[1]));
$data[$kv[0]] = $kv[1];
}
$nodes[$i] = $data;
}
}
return $nodes[count($nodes)-1];
}
Note that it does not catch errors or bad formatting...
For your situation, it looks like you'd want to add {}'s around it (as json_decode also requires):
$data = loose_json_decode('{' . $json . '}');
which for me yields:
array(6) {
["id"]=>
int(43015)
["name"]=>
string(8) "John Doe"
["level"]=>
int(15)
["systems"]=>
array(1) {
[0]=>
array(5) {
["t"]=>
int(6)
["glr"]=>
int(1242)
["n"]=>
string(6) "server"
["s"]=>
int(185)
["c"]=>
int(9)
}
}
["classs"]=>
int(0)
["subclass"]=>
int(5)
}
$json = preg_replace('/([{,])(\s*)([A-Za-z0-9_\-]+?)\s*:/','$1"$3":',$json);// adding->(")
$json = str_replace("'",'"', $json);// replacing->(')
This solution seems to be enough for most common purposes.
I'd say your best bet is to download the source of a JSON decoder (they're not huge) and fiddle with it, especially if you know what's wrong with the JSON you're trying to decode.
The example you provided needs { } around it, too, which may help.
This is my solution to remove trailing/leading/multi commas. It can be combined with other answers that remove single quotes and add quotes around json keys. I realize this would not be relevant to the OP as it deals with other types of invalid json however I just hope to help someone who finds this question on a google search.
function replace_unquoted_text ($json, $f)
{
$matches = array();
preg_match_all('/(")(?:(?=(\\\\?))\2.)*?\1/', $json, $matches, PREG_OFFSET_CAPTURE);
//echo '<pre>' . json_encode($matches[0]) . '</pre>';
$matchIndexes = [0];
foreach ($matches[0] as $match)
{
array_push($matchIndexes, $match[1]);
array_push($matchIndexes, strlen($match[0]) + $match[1]);
}
array_push($matchIndexes, strlen($json));
$components = [];
for ($n = 0; $n < count($matchIndexes); $n += 2)
{
$startIDX = $matchIndexes[$n];
$finalExclIDX = $matchIndexes[$n + 1];
//echo $startIDX . ' -> ' . $finalExclIDX . '<br>';
$len = $finalExclIDX - $startIDX;
if ($len === 0) continue;
$prevIDX = ($n === 0) ? 0 : $matchIndexes[$n - 1];
array_push($components, substr($json, $prevIDX, $startIDX - $prevIDX));
array_push($components, $f(substr($json, $startIDX, $len)));
array_push($components, substr($json, $finalExclIDX, ((($n + 1) === count($matchIndexes)) ? count($json) : $matchIndexes[$n + 1]) - $finalExclIDX));
}
//echo '<pre>' . json_encode($components) . '</pre>';
return implode("", $components);
}
function json_decode_lazy ($jsonSnip) {
return json_decode(fix_lazy_json($jsonSnip));
}
function fix_lazy_json ($json) {
return replace_unquoted_text($json, 'fix_lazy_snip');
}
function fix_lazy_snip ($jsonSnip) {
return remove_multi_commas_snip(remove_leading_commas_snip(remove_trailing_commas_snip($jsonSnip)));
}
function remove_leading_commas ($json) {
return replace_unquoted_text($json, 'remove_leading_commas_snip');
}
function remove_leading_commas_snip ($jsonSnip) {
return preg_replace('/([{[]\s*)(,\s*)*/', '$1', $jsonSnip);
}
function remove_trailing_commas ($json) {
return replace_unquoted_text($json, 'remove_trailing_commas_snip');
}
function remove_trailing_commas_snip ($jsonSnip) {
return preg_replace('/(,\s*)*,(\s*[}\]])/', '$2', $jsonSnip);
}
function remove_multi_commas ($json) {
return replace_unquoted_text($json, 'remove_multi_commas_snip');
}
function remove_multi_commas_snip ($jsonSnip) {
return preg_replace('/(,\s*)+,/', ',', $jsonSnip);
}
json_decode_lazy('[,,{,,,"a":17,,, "b":13,,,,},,,]') // {"a":17, "b":13}
See on repl.it.
I've got a multidimensional associative array which includes an elements like
$data["status"]
$data["response"]["url"]
$data["entry"]["0"]["text"]
I've got a strings like:
$string = 'data["status"]';
$string = 'data["response"]["url"]';
$string = 'data["entry"]["0"]["text"]';
How can I convert the strings into a variable to access the proper array element? This method will need to work across any array at any of the dimensions.
PHP's variable variables will help you out here. You can use them by prefixing the variable with another dollar sign:
$foo = "Hello, world!";
$bar = "foo";
echo $$bar; // outputs "Hello, world!"
Quick and dirty:
echo eval('return $'. $string . ';');
Of course the input string would need to be be sanitized first.
If you don't like quick and dirty... then this will work too and it doesn't require eval which makes even me cringe.
It does, however, make assumptions about the string format:
<?php
$data['response'] = array(
'url' => 'http://www.testing.com'
);
function extract_data($string) {
global $data;
$found_matches = preg_match_all('/\[\"([a-z]+)\"\]/', $string, $matches);
if (!$found_matches) {
return null;
}
$current_data = $data;
foreach ($matches[1] as $name) {
if (key_exists($name, $current_data)) {
$current_data = $current_data[$name];
} else {
return null;
}
}
return $current_data;
}
echo extract_data('data["response"]["url"]');
?>
This can be done in a much simpler way. All you have to do is think about what function PHP provides that creates variables.
$string = 'myvariable';
extract(array($string => $string));
echo $myvariable;
done!
You can also use curly braces (complex variable notation) to do some tricks:
$h = 'Happy';
$n = 'New';
$y = 'Year';
$wish = ${$h.$n.$y};
echo $wish;
Found this on the Variable variables page:
function VariableArray($data, $string) {
preg_match_all('/\[([^\]]*)\]/', $string, $arr_matches, PREG_PATTERN_ORDER);
$return = $arr;
foreach($arr_matches[1] as $dimension) { $return = $return[$dimension]; }
return $return;
}
I was struggling with that as well,
I had this :
$user = array('a'=>'alber', 'b'=>'brad'...);
$array_name = 'user';
and I was wondering how to get into albert.
at first I tried
$value_for_a = $$array_name['a']; // this dosen't work
then
eval('return $'.$array_name['a'].';'); // this dosen't work, maybe the hoster block eval which is very common
then finally I tried the stupid thing:
$array_temp=$$array_name;
$value_for_a = $array_temp['a'];
and this just worked Perfect!
wisdom, do it simple do it stupid.
I hope this answers your question
You would access them like:
print $$string;
You can pass by reference with the operator &. So in your example you'll have something like this
$string = &$data["status"];
$string = &$data["response"]["url"];
$string = &$data["entry"]["0"]["text"];
Otherwise you need to do something like this:
$titular = array();
for ($r = 1; $r < $rooms + 1; $r ++)
{
$title = "titular_title_$r";
$firstName = "titular_firstName_$r";
$lastName = "titular_lastName_$r";
$phone = "titular_phone_$r";
$email = "titular_email_$r";
$bedType = "bedType_$r";
$smoker = "smoker_$r";
$titular[] = array(
"title" => $$title,
"first_name" => $$firstName,
"last_name" => $$lastName,
"phone" => $$phone,
"email" => $$email,
"bedType" => $$bedType,
"smoker" => $$smoker
);
}
There are native PHP function for this:
use http://php.net/manual/ru/function.parse-str.php (parse_str()).
don't forget to clean up the string from '"' before parsing.
Perhaps this option is also suitable:
$data["entry"]["0"]["text"];
$string = 'data["entry"]["0"]["text"]';
function getIn($arr, $params)
{
if(!is_array($arr)) {
return null;
}
if (array_key_exists($params[0], $arr) && count($params) > 1) {
$bf = $params[0];
array_shift($params);
return getIn($arr[$bf], $params);
} elseif (array_key_exists($params[0], $arr) && count($params) == 1) {
return $arr[$params[0]];
} else {
return null;
}
}
preg_match_all('/(?:(\w{1,}|\d))/', $string, $arr_matches, PREG_PATTERN_ORDER);
array_shift($arr_matches[0]);
print_r(getIn($data, $arr_matches[0]));
P.s. it's work for me.