I'm trying to parse the following format with PHP:
// This is a comment
{
this is an entry
}
{
this is another entry
}
{
entry
{entry within entry}
{entry within entry}
}
Maybe is just the lack of caffeine, but i can't think of a decent way of getting the contents of the curly braces.
This is quite a common parsing task, basically you need to keep track of the various states you can be in and use a combination of constants and function calls to maintain them.
Here is some rather inelegant code that does just that:
<?php
$input = file_get_contents('input.txt');
define('STATE_CDATA', 0);
define('STATE_COMMENT', 1);
function parseBrace($input, &$i)
{
$parsed = array(
'cdata' => '',
'children' => array()
);
$length = strlen($input);
$state = STATE_CDATA;
for(++$i; $i < $length; ++$i) {
switch($input[$i]) {
case '/':
if ('/' === $input[$i+1]) {
$state = STATE_COMMENT;
++$i;
} if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
break;
case '{':
if (STATE_CDATA === $state) {
$parsed['children'][] = parseBrace($input, $i);
}
break;
case '}':
if (STATE_CDATA === $state) {
break 2; // for
}
break;
case "\n":
if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
$state = STATE_CDATA;
break;
default:
if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
}
}
return $parsed;
}
function parseInput($input)
{
$parsed = array(
'cdata' => '',
'children' => array()
);
$state = STATE_CDATA;
$length = strlen($input);
for($i = 0; $i < $length; ++$i) {
switch($input[$i]) {
case '/':
if ('/' === $input[$i+1]) {
$state = STATE_COMMENT;
++$i;
} if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
break;
case '{':
if (STATE_CDATA === $state) {
$parsed['children'][] = parseBrace($input, $i);
}
break;
case "\n":
if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
$state = STATE_CDATA;
break;
default:
if (STATE_CDATA === $state) {
$parsed['cdata'] .= $input[$i];
}
}
}
return $parsed;
}
print_r(parseInput($input));
This produces the following output:
Array
(
[cdata] =>
[children] => Array
(
[0] => Array
(
[cdata] =>
this is an entry
[children] => Array
(
)
)
[1] => Array
(
[cdata] =>
this is another entry
[children] => Array
(
)
)
[2] => Array
(
[cdata] =>
entry
[children] => Array
(
[0] => Array
(
[cdata] => entry within entry
[children] => Array
(
)
)
[1] => Array
(
[cdata] => entry within entry
[children] => Array
(
)
)
)
)
)
)
You'll probably want to clean up all the whitespace but some well placed trim's will sort that for you.
This may not be the best solution for large amount of content, but it works.
<?php
$text = "I am out of the brackets {hi i am in the brackets} Back out { Back in}";
print $text . '<hr />';
$tmp = explode("{",$text);
$tmp2 = array();
$wantedText = array();
for($i = 0; $i < count($tmp); $i++){
if(stristr($tmp[$i],"}")){
$tmp2 = explode("}",$tmp[$i]);
array_push($wantedText,$tmp2[0]);
}
}
print_r($wantedText);
?>
Results:
Array ( [0] => hi i am in the brackets [1] => Back in )
Related
i am new on stackoverflow. I have a question. How do this code more appropiate for value replacement in nested arrays?
For example, i have this array obtained from json file:
$json_file = "template.json";
$json = file_get_contents($json_file);
$array = json_decode($json, true);
Now, i obtain the array $res that contain certain searched value:
function array_recursive_search_key_map($needle, $haystack) {
foreach($haystack as $first_level_key=>$value) {
if ($needle === $value) {
return array($first_level_key);
} elseif (is_array($value)) {
$callback = array_recursive_search_key_map($needle, $value);
if ($callback) {
return array_merge(array($first_level_key), $callback);
}
}
}
return false;
}
$res = array_recursive_search_key_map("id|logo", $array);
Doing this, $res contains the position of the searched value in nested $array:
$res = ["content",0,"elements",0,"elements",0,"elements",0,"elements",0,"settings","_attributes"]
I want to replace progamatically the value in:
$array["content"][0]["elements"][0]["elements"][0]["elements"][0]["elements"][0]["settings"]["_attributes"] = "some new value";
I was created a new function but i think are not very practically:
function recursive_replacement($keymap, $newvalue)
{
$size = sizeof($keymap);
switch ($size)
{
case 1:
$array[$keymap[0]] = $newvalue;
break;
case 2:
$array[$keymap[0]][$keymap[1]] = $newvalue;
break;
case 3:
$array[$keymap[0]][$keymap[1]][$keymap[2]] = $newvalue;
break;
case 4:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]] = $newvalue;
break;
case 5:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]] = $newvalue;
break;
case 6:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]][$keymap[5]] = $newvalue;
break;
case 7:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]][$keymap[5]][$keymap[6]] = $newvalue;
break;
case 8:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]][$keymap[5]][$keymap[6]][$keymap[7]] = $newvalue;
break;
case 9:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]][$keymap[5]][$keymap[6]][$keymap[7]][$keymap[8]] = $newvalue;
break;
case 10:
$array[$keymap[0]][$keymap[1]][$keymap[2]][$keymap[3]][$keymap[4]][$keymap[5]][$keymap[6]][$keymap[7]][$keymap[8]][$keymap[9]] = $newvalue;
break;
}
return $array;
}
And the use way:
$new_array = recursive_replacement($res, "some new value");
Any suggestion would be appreciated. Thanks!
At the very first step we need a notation to address an item in an array, i like the dot notation
$array = [
'item_1' => [
'item_2' => 1,
'item_3' => [
'item_4',
'item_5'
]
]
];
For example 'item_1.item_3.0' instead of $array['item_1']['item_3'][0]
Now we need to iterate on our address key and find destination element
function replaceArrayItem($searchKey, $replacement, $array) {
$itemAddressBlocks = explode('.', $searchKey); // convert to array so we can iterate on address
$replacedArray = $array;
$temp = &$replacedArray; // pass by reference
foreach($itemAddressBlocks as $depth => $index) {
if( $depth < sizeof($itemAddressBlocks) - 1 ) { // rolling in the deep :)
$temp = &$temp[$index];
continue;
}
$temp[$index] = $replacement; // last step and replacement
}
return $replacedArray;
}
Now lets test our new function
/**
Array
(
[item_1] => ***replacedItem***
)
**/
print_r( replaceArrayItem('item_1', 'replacedItem', $array) );
/**
Array
(
[item_1] => Array
(
[item_2] => ***replacedItem***
[item_3] => Array
(
[0] => item_4
[1] => item_5
)
)
)
**/
print_r( replaceArrayItem('item_1.item_2', 'replacedItem', $array) );
/**
Array
(
[item_1] => Array
(
[item_2] => 1
[item_3] => Array
(
[0] => item_4
[1] => ***replacedItem***
)
)
)
**/
print_r( replaceArrayItem('item_1.item_3.1', 'replacedItem', $array) );
Now You can progamatically
$itemAddress = 'content.0';
for($i =0; $i < 4; $i++) {
$itemAddress .= '.elements.0';
}
$itemAddress .= '.settings._attributes';
replaceArrayItem($itemAddress, $yourValue, $array);
I want to make a sitemap generator and the generated sitemap must be be like a tree.Can someone point me to an algorithm that does this? Or does anyone know the algorithm?
The structure of the sitemap should look like something like this :
I was thinking to use arrays to do this but i can't think of an algorithm to get all links from the website and build the arrays.
I came up with
<?php
$links = array('bla.com/bla1/bla2', 'bla.com/bla1', 'bla.com/bla1/bla3', 'bla.com', 'bla.com/blabla/bla1/bla4', 'bla.com/blabla/otherbla/onemorebla');
$links = array_fill_keys($links, 0);
foreach($links as $key => $value){
$levelsNumber = count(explode('/', $key));
$links[$key] = $levelsNumber;
}
$output = array();
$maxLevel = 1;
foreach ($links as $link => $levels){
if ($levels > $maxLevel) $maxLevel = $levels;
}
for($level = 1; $level <= $maxLevel; $level++){
foreach ($links as $link => $levels){
$parts = explode('/', $link);
if (count($parts) >= $level){
$levelExists = false;
if (!$levelExists){
$keysString = '';
for ($j = 0; $j < $level; $j++){
$keysString .= "['".$parts[$j]."']";
}
eval('$output'.$keysString.'= NULL;');
$levelExists = true;
}
}
}
}
print_r($output);
?>
running it gives
Array
(
[bla.com] => Array
(
[bla1] => Array
(
[bla2] =>
[bla3] =>
)
[blabla] => Array
(
[bla1] => Array
(
[bla4] =>
)
[otherbla] => Array
(
[onemorebla] =>
)
)
)
)
I think if you play with it you might get what you've expected.
Please help me to extract and display the values from this array..
This is the output when I do a print_r($array); :
Array
(
[0] => SPD Object
(
[DRIVERNAME] => SPD Barry
[STARTTIME] => 07:44
[FINISHTIME] => 18:12
[STOP] =>
[SEQUENCENO] => 37
[PLACENAME] => AMSTERDAM ZUIDOOST
[ARRIVALTIME] => 17:32
)
[1] => SPD Object
(
[DRIVERNAME] => SPD Brady
[STARTTIME] => 07:36
[FINISHTIME] => 15:53
[STOP] =>
[SEQUENCENO] => 32
[PLACENAME] => NIEUWEGEIN
[ARRIVALTIME] => 15:30
)
[2] => SPD Object
(
[DRIVERNAME] => SPD Bram
[STARTTIME] => 08:11
[FINISHTIME] => 18:32
[STOP] =>
[SEQUENCENO] => 32
[PLACENAME] => LAGE ZWALUWE
[ARRIVALTIME] => 17:28
)
)
What I want to do is, get this Driver Name and Sequence Number and echo them.
UPDATE :
My full code can be found below.
I get a xml file which contain this kind of stuff :
<TRIP>
<DRIVERNAME>SPD Barry</DRIVERNAME>
<STARTTIME>07:44</STARTTIME>
<FINISHTIME>18:12</FINISHTIME>
<STOP>
<SEQUENCENO>1</SEQUENCENO>
<PLACENAME>ROTTERDAM</PLACENAME>
<ARRIVALTIME>08:30</ARRIVALTIME>
</STOP>
</TRIP>
Here is my PHP file to collect data into an array.
<?php
class SPD {
function SPD ($aa) {
foreach ($aa as $k=>$v)
$this->$k = $aa[$k];
}
}
function readDatabase($filename) {
// read the XML database of aminoacids
$data = implode("", file($filename));
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, $data, $values, $tags);
xml_parser_free($parser);
// loop through the structures
foreach ($tags as $key=>$val) {
if ($key == "TRIP") {
$molranges = $val;
// each contiguous pair of array entries are the
// lower and upper range for each molecule definition
for ($i=0; $i < count($molranges); $i+=2) {
$offset = $molranges[$i] + 1;
$len = $molranges[$i + 1] - $offset;
$tdb[] = parseMol(array_slice($values, $offset, $len));
}
} else {
continue;
}
}
return $tdb;
}
function parseMol($mvalues) {
for ($i=0; $i < count($mvalues); $i++) {
$mol[$mvalues[$i]["tag"]] = $mvalues[$i]["value"];
}
return new SPD($mol);
}
$db = readDatabase("test.xml");
if(is_array($db)){
foreach($db as $item) {
echo $item->DRIVERNAME;
echo $item->SEQUENCENO;
}
}
?>
What I want to do is, echo Driver name and Sequence Number :)
This should do it :
<?php
class SPD {
function SPD($aa) {
foreach ($aa as $k => $v)
$this->$k = $aa[$k];
}
}
function readDatabase($filename) {
// read the XML database of aminoacids
$data = implode("", file($filename));
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, $data, $values, $tags);
xml_parser_free($parser);
// loop through the structures
foreach ($tags as $key => $val) {
if ($key == "TRIP") {
$molranges = $val;
// each contiguous pair of array entries are the
// lower and upper range for each molecule definition
for ($i = 0; $i < count($molranges); $i+=2) {
$offset = $molranges[$i] + 1;
$len = $molranges[$i + 1] - $offset;
$tdb[] = parseMol(array_slice($values, $offset, $len));
}
} else {
continue;
}
}
return $tdb;
}
function parseMol($mvalues) {
for ($i = 0; $i < count($mvalues); $i++) {
if(isset($mvalues[$i]["value"])) {
$mol[$mvalues[$i]["tag"]] = $mvalues[$i]["value"];
}
}
return new SPD($mol);
}
$db = readDatabase("test.xml");
if (is_array($db)) {
foreach ($db as $item) {
echo 'ITEM 1 : ' . "\n<br/>";
echo '---------------' . "\n<br/>";
echo 'DRIVERNAME : ' . $item->DRIVERNAME . "\n<br/>";
echo 'SEQUENCENO : ' . $item->SEQUENCENO . "\n\n<br/><br/>";
}
}
?>
I have following array
Array
(
[0] => Array
(
[data] => PHP
[attribs] => Array
(
)
[xml_base] =>
[xml_base_explicit] =>
[xml_lang] =>
)
[1] => Array
(
[data] => Wordpress
[attribs] => Array
(
)
[xml_base] =>
[xml_base_explicit] =>
[xml_lang] =>
)
)
one varialbe like $var = 'Php, Joomla';
I have tried following but not working
$key = in_multiarray('PHP', $array,"data");
function in_multiarray($elem, $array,$field)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom][$field] == $elem)
return true;
else
if(is_array($array[$bottom][$field]))
if(in_multiarray($elem, ($array[$bottom][$field])))
return true;
$bottom++;
}
return false;
}
so want to check if any value in $var is exists in array(case insensitive)
How can i do it without loop?
This should work for you:
(Put a few comments in the code the explain whats goning on)
<?php
//Array to search in
$array = array(
array(
"data" => "PHP",
"attribs" => array(),
"xml_base" => "",
"xml_base_explicit" => "",
"xml_lang" => ""
),
array(
"data" => "Wordpress",
"attribs" => array(),
"xml_base" => "",
"xml_base_explicit" => "",
"xml_lang" => "Joomla"
)
);
//Values to search
$var = "Php, Joomla";
//trim and strtolower all search values and put them in a array
$search = array_map(function($value) {
return trim(strtolower($value));
}, explode(",", $var));
//function to put all non array values into lowercase
function tolower($value) {
if(is_array($value))
return array_map("tolower", $value);
else
return strtolower($value);
}
//Search needle in haystack
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}
return false;
}
//Search ever value in array
foreach($search as $value) {
if(in_array_r($value, array_map("tolower", array_values($array))))
echo $value . " found<br />";
}
?>
Output:
php found
joomla found
to my understanding , you are trying to pass the string ex : 'php' and the key : 'data' of the element .
so your key can hold a single value or an array .
$key = in_multiarray("php", $array,"data");
var_dump($key);
function in_multiarray($elem, $array,$field)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if(is_array($array[$bottom][$field]))
{
foreach($array[$bottom][$field] as $value)
{
if(strtolower(trim($value)) == strtolower(trim($elem)))
{
return true;
}
}
}
else if(strtolower(trim($array[$bottom][$field])) == strtolower(trim($elem)))
{
return true;
}
$bottom++;
}
return false;
}
i have a unserialized array
like this
Array (
[status] => 1
[msg] => Transaction Fetched Successfully
[transaction_details] => Array (
[100002982] => Array (
[mihpayid] => 4149968
[request_id] => 635788
[bank_ref_num] => NINETE.31845.28052012
[amt] => 3295.00
[disc] => 0.00
[mode] => CC
[retries] => 0
[status] => success
[unmappedstatus] => captured
)
)
)
i want to parse this array
so that i can get the value to status ie Success
how i can do that
$success = $array['transaction_details']['100002982']['status'];
$arr['transaction_details']['100002982']['status']
The PHP documentation has a user comment which suggests a method to parse the output of print_r (similar to the above). It can be found here: http://www.php.net/manual/en/function.print-r.php#93529
Here is a copy of the source code found at the above link:
<?php
function print_r_reverse($in) {
$lines = explode("\n", trim($in));
if (trim($lines[0]) != 'Array') {
// bottomed out to something that isn't an array
return $in;
} else {
// this is an array, lets parse it
if (preg_match("/(\s{5,})\(/", $lines[1], $match)) {
// this is a tested array/recursive call to this function
// take a set of spaces off the beginning
$spaces = $match[1];
$spaces_length = strlen($spaces);
$lines_total = count($lines);
for ($i = 0; $i < $lines_total; $i++) {
if (substr($lines[$i], 0, $spaces_length) == $spaces) {
$lines[$i] = substr($lines[$i], $spaces_length);
}
}
}
array_shift($lines); // Array
array_shift($lines); // (
array_pop($lines); // )
$in = implode("\n", $lines);
// make sure we only match stuff with 4 preceding spaces (stuff for this array and not a nested one)
preg_match_all("/^\s{4}\[(.+?)\] \=\> /m", $in, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
$pos = array();
$previous_key = '';
$in_length = strlen($in);
// store the following in $pos:
// array with key = key of the parsed array's item
// value = array(start position in $in, $end position in $in)
foreach ($matches as $match) {
$key = $match[1][0];
$start = $match[0][1] + strlen($match[0][0]);
$pos[$key] = array($start, $in_length);
if ($previous_key != '') $pos[$previous_key][1] = $match[0][1] - 1;
$previous_key = $key;
}
$ret = array();
foreach ($pos as $key => $where) {
// recursively see if the parsed out value is an array too
$ret[$key] = print_r_reverse(substr($in, $where[0], $where[1] - $where[0]));
}
return $ret;
}
}
?>
I have not tested the above function.