...

View Full Version : Create Array from formated text file - sort of formated



IanDMac
09-05-2009, 12:29 PM
Hi all,

Please forgive if this is what you experts would call basic, but I am trying to learn and after weeks of different attempts (failures) and too many books and web sites to mention, would appreciate some pointers on creating one or more arrays from a text file, where the text file does not have a single or straight forward explode usage ability.

The file I am trying to create the arrays from has quite a bit of differing information in it, which in its fullest complete form could look like this (but can change obviously):


220900;
$::g_pDiscountBlob =
{
'VERSION' => 2,
'ONE_PRODUCT_DISCOUNT' => 0,
'ONE_ORDER_DISCOUNT' => '0',
'ONE_ORDER_DISCOUNT_SURCHAGE' => '0',
'COUPON_ON_CART' => 0,
'COUPON_ON_CHECKOUT' => 1,
'COUPON_ON_PRODUCT' => 0,
'CONSOLIDATE_MONEY_OFF' => 1,
'CONSOLIDATE_PERCENTAGE_OFF' => 0,
'CONSOLIDATE_PERCENTAGE_OFF_CHEAPEST' => 0,
'CONSOLIDATE_MONEY_OFF_EXTRA' => 0,
'CONSOLIDATE_PERCENTAGE_OFF_EXTRA' => 0,
'CONSOLIDATE_FIXED_PRICE' => 0,
'ORDER_LEVEL' => [
{
'ID' => 1,
'TYPE' => 0,
'DESCRIPTION' => 'Order Value no Code - Perc',
'REWARD_TYPE' => 1,
'BASIS' => 0,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'10000' => '-5.00%',
'20000' => '-6.00%',
'40000' => '-7.50%',
'100000' => '-12.50%',
},
'RESTRICTIONS' => {
'C_2' => 1,
},
},

{
'ID' => 4,
'TYPE' => 0,
'DESCRIPTION' => 'Order Value with Code - Perc',
'REWARD_TYPE' => 1,
'BASIS' => 2,
'REQUIRES_COUPON' => 1,
'COUPON_CODE' => '25f9e794323b453885f5181f1b624d0b',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'5000' => '-5.00%',
'10000' => '-10.00%',
'20000' => '-15.00%',
},
'RESTRICTIONS' => {
},
},

{
'ID' => 5,
'TYPE' => 0,
'DESCRIPTION' => 'Order Value no Code - Amt',
'REWARD_TYPE' => 0,
'BASIS' => 2,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'10000' => '-2500',
'50000' => '-3500',
},
'RESTRICTIONS' => {
},
},

{
'ID' => 6,
'TYPE' => 0,
'DESCRIPTION' => 'Ex Vat discount Amt',
'REWARD_TYPE' => 0,
'BASIS' => 0,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'300000' => '-40000',
},
'RESTRICTIONS' => {
},
},

{
'ID' => 7,
'TYPE' => 0,
'DESCRIPTION' => 'Restricted date perc',
'REWARD_TYPE' => 1,
'BASIS' => 0,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 1,
'USE_UNTIL_DATE' => 1,
'VALID_FROM' => '2009/09/04',
'VALID_UNTIL' => '2009/10/04',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'500000' => '-35.00%',
},
'RESTRICTIONS' => {
},
},

],

'PRODUCT_LEVEL' => [
{
'ID' => 2,
'TYPE' => 1,
'DESCRIPTION' => '3 for the price of 2',
'REWARD_TYPE' => 2,
'BASIS' => 3,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => 1,
'REWARDS' => {
'TRIGGER' => 3,
'USE_GROUP' => 0,
'MONEY_OFF' => 0,
'PERCENTAGE_OFF' => '100.00%',
'PRODUCT_GROUP' => -1,
'PRODUCT_REF' => '',
},
'RESTRICTIONS' => {
},
},

],
'PRODUCT_GROUPS' =>

{
'1' => [
0,
'Books',
''
],
}
};
return($::SUCCESS);


The first array, I would need to create is based on this section:


'VERSION' => 2,
'ONE_PRODUCT_DISCOUNT' => 0,
'ONE_ORDER_DISCOUNT' => '0',
'ONE_ORDER_DISCOUNT_SURCHAGE' => '0',
'COUPON_ON_CART' => 0,
'COUPON_ON_CHECKOUT' => 1,
'COUPON_ON_PRODUCT' => 0,
'CONSOLIDATE_MONEY_OFF' => 1,
'CONSOLIDATE_PERCENTAGE_OFF' => 0,
'CONSOLIDATE_PERCENTAGE_OFF_CHEAPEST' => 0,
'CONSOLIDATE_MONEY_OFF_EXTRA' => 0,
'CONSOLIDATE_PERCENTAGE_OFF_EXTRA' => 0,
'CONSOLIDATE_FIXED_PRICE' => 0,
'ORDER_LEVEL' => [

But, then would need to create unique arrays for sections like this:


{
'ID' => 1,
'TYPE' => 0,
'DESCRIPTION' => 'Order Value no Code - Perc',
'REWARD_TYPE' => 1,
'BASIS' => 0,
'REQUIRES_COUPON' => 0,
'COUPON_CODE' => 'd41d8cd98f00b204e9800998ecf8427e',
'USE_FROM_DATE' => 0,
'USE_UNTIL_DATE' => 0,
'VALID_FROM' => '',
'VALID_UNTIL' => '',
'RESTRICTED_TO_PAYMENT' => 0,
'RESTRICTED_TO_CUSTOMER' => 0,
'CART_DESC' => '',
'ONE_PER_ORDER' => 0,
'GROUPID' => -1,
'REWARDS' => {
'10000' => '-5.00%',
'20000' => '-6.00%',
'40000' => '-7.50%',
'100000' => '-12.50%',
},
'RESTRICTIONS' => {
'C_2' => 1,
},
},

Where the array is created based on the Type => x , so all '0' into a multi array, and all '1' into a multi array and so on.

My problem that I keep hitting is that every time I read through the lines, my different attempts at Start TYPE 0 create arrays and then stop at end, and explode key => populates nothing, although I know the file is being read ok as I can echo it all out ok line by line.

Any pointers would be appreciated as not expecting the solution to it all.

Thanks for any assistance in advance.

Ian

bacterozoid
09-05-2009, 01:41 PM
This could be quite complicated. The only advice I can give you right now is to build your script based on the general case...ie: your second example. You don't want to have to write 4 different scripts that do basically the same thing.

My guess is that you'll want to read the file line by line and look for specific elements to trigger what you want to do.

For instance, when you read:


'ID' => 1,

You can look for the string "=>" and know you have an assignment...so explode on the '=>', strip the quotes, spaces, and comma, then do $array[$firstHalf] = $secondHalf.

Or if you get to lines like this:


'REWARDS' => {

You can see the bracket at the end and know you need to begin a new array. I think a recursive function would be the best way to go.

IanDMac
09-05-2009, 02:34 PM
Hi bacterozoid,

Thanks for the suggestions, will see what I can achieve after stripping out some of the other bits.

Thanks again.

Ian

IanDMac
09-05-2009, 06:12 PM
OK - took the approach that I want to get the first array of the overall Version data collected into an array and will then look at how best to get the ID's into arrays as per the number after them... anyway, this is what I have come up with so far, which gives me an end array based on key (from the original name)... no doubt better ways of achieving what I have done so far, so any input would be greatly appreciated on improvements or where I may have gone wrong...


function StripLine($line)
// Remove all tabs, carriage returns, line feeds and spaces
{
$origline = trim($line, " \t \n \r"); // remove tabs and line feeds
$replacewith = array("","",""); // blank replacements
$findreplace = array("'",","," "); // characters to remove/replace
$reply = str_replace($findreplace, $replacewith, $origline);
return $reply; // send back cleaned string
}

function CreateSettingsArray($sourceline, $file)
// Create array containing all of the settings and directions
{
$entries = explode("=>", $sourceline); // create array of 2 items
$settings[$entries[0]] = $entries[1]; // turn 2 items into key and value
while (strcmp($sourceline, "{") <> 0)
{
$begin = fgets($file); // Get the next line from source file
$sourceline = StripLine($begin); // Call strip of unwanted content and get cleaned string back
$entries = explode("=>", $sourceline); // create array of 2 items
$settings[$entries[0]] = $entries[1]; // turn 2 items into key and value
}
echo "Version for settings is " . $settings['VERSION'] . "<br>"; // echo value based on key request to see if it works
echo "One Product Discount is " . $settings['ONE_PRODUCT_DISCOUNT'] . "<br>";
echo "One Order Discount is " . $settings['ONE_ORDER_DISCOUNT'] . "<br>";
echo "One Order Discount Surcharge is " . $settings['ONE_ORDER_DISCOUNT_SURCHAGE'] . "<br>";
echo "Coupon on cart is " . $settings['COUPON_ON_CART'] . "<br>";
echo "Coupon on checkout is " . $settings['COUPON_ON_CHECKOUT'] . "<br>";
echo "Coupon on product is " . $settings['COUPON_ON_PRODUCT'] . "<br>";
echo "Consolidate money off is " . $settings['CONSOLIDATE_MONEY_OFF'] . "<br>";
echo "Consolidate percentage off is " . $settings['CONSOLIDATE_PERCENTAGE_OFF'] . "<br>";
echo "Consolidate percentage off cheapest is " . $settings['CONSOLIDATE_PERCENTAGE_OFF_CHEAPEST'] . "<br>";
echo "Consolidate money off extra is " . $settings['CONSOLIDATE_MONEY_OFF_EXTRA'] . "<br>";
echo "Consolidate percentage off extra is " . $settings['CONSOLIDATE_PERCENTAGE_OFF_EXTRA'] . "<br>";
echo "Consolidate fixed price is " . $settings['CONSOLIDATE_FIXED_PRICE'] . "<br>";
}

// Open the text file with source data
$file = fopen("my-source-file.txt", "r") or exit("Unable to open file!"); // Open source file
while(!feof($file)) // rotate through file line by line

{
$begin = fgets($file); // Get the next line from source file
$cleanline = StripLine($begin); // Call strip of unwanted content and get cleaned string back
$lookfor = "VERSION=>2"; // string to match which is VERSION
if (strcmp($cleanline, $lookfor) == 0) { CreateSettingsArray($cleanline, $file); } else
{ echo $cleanline."<br>"; }
}

fclose($file);
exit;

What I could not work out was how to create a Keyed array, without exploding to 2 items in an array first, and then creating the keyed array from those - a means to an end, but want to learn the best ways rather than longest ways lol.

Thanks, Ian

bacterozoid
09-06-2009, 12:30 PM
So let me get this straight:

You have a high level structure with properties such as version, one_product_discount, etc. This high level structure has sub-structures like order_level, product_level, and product_groups. Each of those sub-structures can have sub structures of their own. You just want to drop all of that into a big old multi-dimensional associative array?

Also, what's generating this data? It's not consistent. Take this line:


'ORDER_LEVEL' => [
{


The square bracket indicates an array is coming up, but is then followed by a curly bracket on the next line.

Now look here:


'REWARDS' => {
'10000' => '-5.00%',

An array is coming up, but there is no square bracket to indicate such. Any reason for this? There's also inconsistency in tabs and spaces in the above example. The first uses tabs, the second uses spaces to separate the => from the rest of the line.

IanDMac
09-06-2009, 02:34 PM
Yes it is well confusing, hense my problems with trying to make something from this data.

The first set of info I class as Version, which has constraints on all of the remaining portions, I have managed to grab into the array explaned and achieved above. After this comes, ID and Types. Each ID is unique and Types can be 0 or 1. My plan is to get all Types = 0 into one array and all Types = 1 into another array, which will need to be multidimensional so like:

valuebased => ID1 (if its ID #1) = Key name = value

Sort of got something working to create the multidimensional array for the 1st line of and keyname and value - got to work out how to get the remaining (columns if you like) for the other elements of that ID...

Thanks for your help, but can see this is a mare to even contemplate, let alone achieve right now, but once I have something which does the job, will post the results and you can tell me where I have gone wrong and could have done better, as I think it will end up being very bloated to achieve the end result of a multidimensional array :(

Thanks again for the interest, Ian

bacterozoid
09-06-2009, 03:04 PM
Give me a couple hours more - I'm putting something together that should do the trick. I enjoy the challenge ;)

bacterozoid
09-06-2009, 04:14 PM
This is buggy right now, but it might help you get an idea. My wife is bugging me to take a break, so I better listen.

I'm using a recursive approach. I read each line and look at it. If it has a square bracket "[" it means that a list of unassociative elements is coming, each separated by { and }. Inside those arrays, there are assignments and sub-arrays and all that. I check for assignments by looking for "=>" and then adding that to the array. Sub-arrays with associative indexes are separated by { and }, with no square brackets.

Again, it's all recursive. I was working with the square bracket stuff but I'm being summoned right now. I'll keep working on it when I get a chance.


<?php

error_reporting(E_ALL);

// Open the text file with source data
$file = fopen("test.txt", "r") or exit("Unable to open file!");

$file = "test.txt";
$handle = @fopen($file, "r");
if ($handle) {

echo '<pre>';
$result = Array();
processLine($handle, nextLine($handle), &$result);
echo '-----------------------------------------------------------------------------------------------------------<br/>';
print_r($result);
echo '</pre>';
fclose($handle); // Close the file handle

}

function processLine($handle, $line, $array, $assoc = true, $index = 0) {
//echo '---------------------------------------------------------------------------------',$line,'<br/>';
// Stop when we reach the end of the file
if($line === false) {
return false;
}

// Skip empty lines
while(empty($line)) {
$line = nextLine($handle);
}

/*
* Determine if this line has a square bracket. If so, that means that a
* simple array is coming up, with elements separated by { and }. This would
* execute on things like ORDER_LEVEL and PRODUCT_LEVEL.
*/
if(strpos($line, '=> [')) { //Need to use !== false because if strpos returns 0, it qualifies as false
//echo 'BEGIN NEW ARRAY: ',$line,'<br/>';
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$array[$elements[0]] = Array(); // Create a new array for the results
processLine($handle, nextLine($handle), &$array[$elements[0]], false, 0); // Non assoc array coming up
}

/*
* If we're on a simple indexed array (ORDER_LEVEL and PRODUCT_LEVEL), then
* look for an opening bracket. If so, ignore it and go to the next line
*/
if(!$assoc and strpos($line, '{')) { //Need to use !== false because if strpos returns 0, it qualifies as false
$line = nextLine($handle);
}

/*
* If we're on a simple indexed array (ORDER_LEVEL and PRODUCT_LEVEL), then
* look for a closing bracket. When we find this, we know this index is
* complete and that we should move on to the next one
*/
if(!$assoc and strpos($line, '}')) {
processLine($handle, nextLine($handle), &$array, false, $index + 1);
}


/*
* If we find the end of an array, indicated by a closing bracket, return
* from the current call - in essence moving back up the structure one
* level.
*/
if(strpos($line, '}') !== false or strpos($line, ']') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
//echo 'RETURNING: ',$line,'<br/>';
return;
}

/*
* Finally, see if the line we are on has an assignment. If so, make that
* assignment.
*/

if(strpos($line, '=>')) {
//print_r($array); echo '<br/><br/>';
//echo 'ASSIGNMENT[',$level,']: ',$line,'<br/>';
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$elements[1] = trim($elements[1]);
$array[$elements[0]] = $elements[1];
}

/*
* If we got this far, the end of the array has not been found, so continue
* to the next line and look for more assignments.
*/
processLine($handle, nextLine($handle), &$array, $assoc, $index);

//return $array;
}

/*
* Get the next line in the file and clean it up
*/
function nextLine($handle) {

// Only return a line if we're not at the end of the file. Otherwise, return
// false
if(!feof($handle)) {
// Clean the line up a bit
$line = cleanLine(fgets($handle, 4096)); //4096 = buffer size in bytes

return $line;
}
else {
return false;
}
}



// Remove all tabs, carriage returns, line feeds and spaces
function cleanLine($line) {
$origline = trim($line, " \t \n \r"); // remove tabs and line feeds
$replacewith = array("","","", " "); // replacements
$findreplace = array("'",","," ", "\t"); // characters to remove/replace
$reply = str_replace($findreplace, $replacewith, $origline);
return $reply; // send back cleaned string
}


?>

IanDMac
09-06-2009, 06:05 PM
Hi thanks,

Am going to grab this and place into a page and digest it, as need to understand the workings of it all, as not one to receive, say thanks and then not understand it, as that serves no pupose other than greed for results, so will go through it and try and understand, for which the comments will be a great help. Understand that this may not be the end solution as buggy like you say, but thanks, will enjoy getting to grips with this to understand its workins out... catch you later hopefully.

Thanks, Ian

bacterozoid
09-06-2009, 06:29 PM
Don't spend too much time trying to understand exactly what I'm doing - it's not near correct enough at this point. If you aren't familiar with recursion, though, that would be a good thing to get a start on.

Also, my method will attempt to solve every case with arrays as deep as necessary. That way if your file changes slightly, you won't have to change the code.

IanDMac
09-06-2009, 06:34 PM
No probs - but whilst you enjoy the challenge of this, I do enjoy picking things up and better understanding the end results, so a happy student (at my age LOL) to review and review until I know what it does and how, but will take your point on not there yet, as seen the restrictions and C_2 appear in the initial array, which has come over from the first ID 1 group, but all good and thanks again for your interest :thumbsup:

bacterozoid
09-06-2009, 07:42 PM
I'll help you understand the code if I figure it out. I can tell you're interested in learning, unlike most who just want the code snippet done for them, which is why I'm happy to take the effort to help.

IanDMac
09-06-2009, 09:00 PM
unlike most who just want the code snippet done for them

I hear you on that.

I appreciate your assistance and guidance - have been reading quite a few threads on recursion and its quite a thing for sure, and as you say, a much better solution than my nested functions with while and if's.

IanDMac
09-07-2009, 01:46 PM
Just seen that the file does have some format to it LOL - did not see the wood for the trees.

The

'ORDER_LEVEL' => [
then contains all of the different order level groups in IDs and { } and at the end of all of the order level ones, then closes the ]

I must have been looking too hard to have missed it LOL, so maybe not so unformated as I thought after all.

bacterozoid
09-07-2009, 01:48 PM
I'm getting closer...just a few bugs left and I think it should work out.


<?php

// Turn on all errors to help debugging
error_reporting(E_ALL);

// Open the file for read only
$file = "test.txt";
$handle = @fopen($file, "r");

// If successfully opened
if ($handle) {

echo '<pre>';
$result = Array(); // Initialize the result array

// This does all the processing recursively
processLine(&$handle, nextLine(&$handle), &$result);

echo '-----------------------------------------------------------------------------------------------------------<br/>';
print_r($result); // Print the result array
echo '</pre>';
fclose($handle); // Close the file handle

}

/*
*
*
* @param handle
* @param line
* @param array
* @param assoc
* @param index
*/
function processLine($handle, $line, $array, $assoc = true, $index = 0) {
echo '---------------------------------------------------------------------------------',$line,'<br/>';
// Stop when we reach the end of the file
if($line === false) {
return false;
}

// Skip empty lines
while(empty($line)) {
$line = nextLine(&$handle);
}

/*
* Determine if this line has a square bracket. If so, that means that a
* simple array is coming up, with elements separated by { and }. This would
* execute on things like ORDER_LEVEL and PRODUCT_LEVEL.
*/
if(strpos($line, '=> [')) {
echo 'BEGIN NONASSOC ARRAY: ',$line,'<br/>';
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$array[$elements[0]] = Array(); // Create a new array for the results
$line = nextLine(&$handle); // The next line is just a "{", so skip it.
echo '---------------------------------------------------------------------------------!',$line,'<br/>';

while(true) {
$line = processLine(&$handle, nextLine(&$handle), &$array[$elements[0]], false, $index); // Go to the next line and continue searching. Expecting a "{"
echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "',$line,'"<br/>';
if(strpos($line, '},') !== false) {
$index++;
echo 'continue';
continue;
}
else {
break;
}
}

}


/*
* Beginning of an associative array
*/
if(strpos($line, '=>{') !== false) {
echo 'START ASSOC ARRAY: ',$line,'<br/>';
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$array[$elements[0]] = Array(); // Create a new array for the results
$line = processLine(&$handle, nextLine(&$handle), &$array[$elements[0]]); // Go to the next line and continue searching.
}


/*
* If we're on a simple indexed array (ORDER_LEVEL and PRODUCT_LEVEL), then
* look for an opening bracket. If so, ignore it and go to the next line

if(!$assoc and strpos($line, '{') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
//echo 'NONASSOC NEW ELEMENT: ',$line,'<br/>';
$line = nextLine($handle);
echo '---------------------------------------------------------------------------------!',$line,'<br/>';
}
*/

/*
* If we're on a simple indexed array (ORDER_LEVEL and PRODUCT_LEVEL), then
* look for a closing bracket. When we find this, we know this index is
* complete and that we should move on to the next one
*/
if(!$assoc and strpos($line, '}') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
echo 'CLOSE NONASSOC ELEMENT: ',$line,'<br/>';
return $line;
//processLine($handle, nextLine($handle), &$array, $assoc, $index);
}

if($assoc and strpos($line, '}') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
echo 'CLOSE ASSOC ELEMENT: ',$line,'<br/>';
return $line;
//processLine($handle, nextLine($handle), &$array, $assoc, $index);
}

/*
* End nonassociative array
*/
if(!$assoc and strpos($line, ']') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
echo 'END NONASSOC ARRAY: ',$line,'<br/>';
return;
//processLine($handle, nextLine($handle), &$array, true, $index + 1);
}

/*
* Finally, see if the line we are on has an assignment. If so, make that
* assignment.
*/

if(strpos($line, '=>')) {
//print_r($array); echo '<br/><br/>';
echo 'ASSIGNMENT: ',$line,'<br/>';
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$elements[1] = trim($elements[1]);
$array[$elements[0]] = $elements[1];
//echo $array,'[',$elements[0],'] = ',$elements[1],'<br/>';
}

/*
* If we got this far, the end of the array has not been found, so continue
* to the next line and look for more assignments.
*/
$line = processLine(&$handle, nextLine(&$handle), &$array, $assoc, $index);

//return $array;
}

/*
* Get the next line in the file and clean it up
*/
function nextLine($handle) {

// Only return a line if we're not at the end of the file. Otherwise, return
// false
if(!feof($handle)) {
// Clean the line up a bit
$line = cleanLine(fgets($handle, 4096)); //4096 = buffer size in bytes

return $line;
}
else {
return false;
}
}



// Remove all tabs, carriage returns, line feeds and spaces
function cleanLine($line) {
$origline = trim($line, " \t \n \r"); // remove tabs and line feeds
$replacewith = array("","","", " "); // replacements
$findreplace = array("'",","," ", "\t"); // characters to remove/replace
$reply = str_replace($findreplace, $replacewith, $origline);
return $reply; // send back cleaned string
}


?>

bacterozoid
09-07-2009, 02:32 PM
Unfortunately this is as far as I can take you. I've tried to comment things pretty well for you. The idea, basically, is to recursively call the processLine function. Recursion gives you the incredible ability to not have to write code more than once. It can be difficult to fully understand and it's a bear to program sometimes, but worth it in the end. Part of the idea is that if you program it for an array that only goes 3 levels deep or so, like this one, it will still work for an array that goes 50 levels deep.

The other important thing here is passing by reference using the & symbol. If done correctly, anytime I change the variable, it changes everywhere.


<?php

// Turn on all errors to help debugging
error_reporting(E_ALL);

// Open the file for read only
$file = "test.txt";
$handle = @fopen($file, "r");

// If successfully opened
if ($handle) {

echo '<pre>';
$result = Array(); // Initialize the result array

/*
* This does recursive processing. Notice the & symbols before the variables.
* That indicates passing by reference...so instead of sending a copy of the
* file handle or a copy of the result array, I actually send the address
* of that variable. This is necessary so that the recursive function modifies
* the correct variable, instead of just creating incomplete copies of
* everything. The handle is especially important to do this way because when
* I read the next line of the file, I don't want to go back to that line.
* Passing by reference keeps the same file handle across the board.
*/
processLine(&$handle, nextLine(&$handle), &$result);

echo '-----------------------------------------------------------------------------------------------------------<br/>';
print_r($result); // Print the result array
echo '</pre>';
fclose($handle); // Close the file handle

}

/*
*
*
* @param handle
* @param line
* @param array
* @param assoc
* @param index
*/
function processLine($handle, $line, $array, $assoc = true, $index = 0) {
// Stop when we reach the end of the file
if($line === false) {
return false;
}

/*
* Determine if this line has a square bracket. If so, that means that a
* simple array is coming up, with elements separated by { and }. This would
* execute on things like ORDER_LEVEL and PRODUCT_LEVEL.
*/
if(strpos($line, '=> [')) {
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$array[$elements[0]] = Array(); // Create a new array for the results
$line = nextLine(&$handle); // The next line is just a "{", so skip it.

// Recursive call
$line = processLine(&$handle, nextLine(&$handle), &$array[$elements[0]], false, $index++);

}


/*
* Beginning of an associative array
*/
if(strpos($line, '=>{') !== false) {
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$array[$elements[0]] = Array(); // Create a new array for the results

// Recursive call
$line = processLine(&$handle, nextLine(&$handle), &$array[$elements[0]]);
}

/*
* If we're on a simple indexed array (ORDER_LEVEL and PRODUCT_LEVEL), then
* look for a closing bracket. When we find this, we know this index is
* complete and that we should move on to the next one
*/
if(strpos($line, '}') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
return $line;
}

/*
* End nonassociative array
*/
if(!$assoc and strpos($line, ']') !== false) { //Need to use !== false because if strpos returns 0, it qualifies as false
return $line;
}

/*
* Finally, see if the line we are on has an assignment. If so, make that
* assignment.
*/
if(strpos($line, '=>')) {
$elements = explode('=>', $line);
$elements[0] = trim($elements[0]);
$elements[1] = trim($elements[1]);
$array[$elements[0]] = $elements[1];
}

/*
* If we got this far, the end of the array has not been found, so continue
* to the next line and look for more assignments.
*/
$line = processLine(&$handle, nextLine(&$handle), &$array, $assoc, $index);

}

/*
* Get the next line in the file and clean it up
*/
function nextLine($handle) {

// Only return a line if we're not at the end of the file. Otherwise, return
// false
if(!feof($handle)) {

$line = '';
// Skip empty lines
while(empty($line)) {
$line = cleanLine(fgets($handle, 4096));
}

return $line;
}
else {
return false;
}
}



// Remove all tabs, carriage returns, line feeds and spaces
function cleanLine($line) {
$origline = trim($line, " \t \n \r"); // remove tabs and line feeds
$replacewith = array("","","", " "); // replacements
$findreplace = array("'",","," ", "\t"); // characters to remove/replace
$reply = str_replace($findreplace, $replacewith, $origline);
return $reply; // send back cleaned string
}


?>


Let me know if you have any questions about it. You may be able to figure it out, you may just have to do something else. Regardless, it's a good way to learn about a few things.

Right now it's kind of working, but I didn't have time to get the non-associative arrays like ORDER_LEVEL to work. It does the first one ok, but then bombs out after that. That's sort of the thing about recursion - there's just one or two small bugs left but they're tough to figure out.

Edit: Just a note - I took the first two lines out of the file when I ran the code. You may or may not have to do that...I think it will work with them, but if not, just take them out or manually skip those lines.

IanDMac
09-07-2009, 02:50 PM
Hi,

I think I am loosely following the recursion (so all good on that front I think), but trying to get my head around the index use. I see and understand its value at the start of the function, but dont follow where its used and purpose of the increment - or am I jumping the gun somewhat and its true use is not realised yet.

This is certainly an eye openner, grant you that with recursion and takes some brain processing as I walk through the code in a linear fashion up and down, back and forth seeing how each line of the arrays are created - sweet :)

IanDMac
09-07-2009, 02:53 PM
Unfortunately this is as far as I can take you.

Thanks, did not see this come in whilst I was penning my last response above.

Will dig into this and come back with my results and any brain waves I have.

Many thanks for your assistance and interest in this - much appreciated.

Thanks, Ian

bacterozoid
09-07-2009, 03:21 PM
Hi,

but trying to get my head around the index use.

My goal with the index was to be able to keep an index for the non associative arrays like the ORDER_LEVEL array. Every time you add a new element (ID=1, ID=4, etc), I increment the index so the new array is created in the correct spot.

IanDMac
09-07-2009, 03:29 PM
k thanks - so is it at present that it just increments, but is not used at present, so I can work on using the increment inline with the { or decrese with } and so on. just to confirm, it not used at present.

bacterozoid
09-07-2009, 03:49 PM
It is used, but it's not really working. Look for anywhere inside the recursive function you see $index.

IanDMac
09-07-2009, 05:31 PM
It is used, but it's not really working. Look for anywhere inside the recursive function you see $index.

Yup, see it.

I see that it increments, but not used at present to provide any decision based upon its value, so will work on that principle I think.

Will let you know how (if) I get on.

Thanks, Ian

IanDMac
09-07-2009, 06:44 PM
I have added some echo statements into the mix where the array elements are added, to give me an idea of what is being added when and how, plus echo out the current index count and notice that whilst I have been able to ensure an increment in the right places, it zero's itself out when it comes to the assoc side, but then continues the count past it, so am trying to work that one out.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum