Jump to content

Need logic ideas


Prismatic

Recommended Posts

Ok so quick rundown,

 

I've created a script to make formatted code for a forum that doesn't have any code posting options.

 

You put your code in and the script runs through each line of the code, splits each line into an array of characters then runs through each line until it hits a non-whitespace character, replacing each space or tab with the appopriate number of periods as it goes along.

 

It's working wonderfully and the code looks great, however you cant copy and paste the code once it's been run through since it's now indented with periods.

 

The idea is to use blockquotes now, which will allow me to indent the code but also preserve the ability for anyone to copy it off the forum without it being trashed with periods, but i'm just not sure how I would go about doing it.

 

Below is a picture of what I mean. Each line represents a line of code, I would need the script to be able to find blocks of indented code and throw a blockquote around groups of indented code.

 

If anyone has any ideas I'd appreciate it. Just looking for ideas here :)

 

blockq.jpg

Link to comment
Share on other sites

be warned: waynewex's way is probably much easier, but i worked hard on this, so i'm gonna post it anyway.  ;D

 

i think i would use 2 variables to save the length of the indent:

$prevIndent  = the previous line's indent.

$curIndent = the current line's indent.

 

compare the 2, and just save all text that has the same amount of indent into an array (each line as 1 element).

in the end, implode the elements around "\n", and stuff the imploded string into a blockquote.

 

all this code should be in recursive function (i hate recursive functions) so that you can find nested indentations. it would look something like this:

 

function findBlockQuotes($fh, $firstStr = ""){ //$firstStr holds the first string of each block. you'll see y.
        $block = array();
        $prevIndent = NULL;
        while($line = fgets($fh)){

              $curIndent = //get the length of the current indent;

              if (is_null($prevIndent)) {$prevIndent = $curIndent;} //prevent going into infinite recursion.

              if($prevIndent < $curIndent){
                   $line = array_pop($block); //get last line, since it's indent level belongs to the parent block
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr;
              }

              else if($prevIndent > $curIndent )  {
                   $tmp = explode("<explodeHere>", findBlockQuotes($fh, $line)); //seperate the block from the next line of current indent level
                   $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
                   $block[] = $tmp[1]; //this is the extra line
               }

              else{
                   $block[] = trim($line); //get rid of indent, because you will nest blockquotes instead
              }
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$fh = fopen(); //you know what to do
$nestedBlocks = '<blockquote>'.findBlockQuotes($fh).'<blockquote>';

 

the code would be similar to this if you're formatting it from text and not from a file.

 

i'm really sorry if the logic in the function is flawed/something doesn't work. my brain feels like mashed potatoes right now...  ;D

 

if you have any questions, please ask.

Link to comment
Share on other sites

This is what I came up with

 

<?php

$code =
"
var = 'Test!';
{
    if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";

function findBlockQuotes($code, $firstStr = ""){ //$firstStr holds the first string of each block. you'll see y.
        $block = array();
        $prevIndent = NULL;

        $lineArray = explode("\n", $code);
        //while($line = fgets($fh)){

        foreach($lineArray as $key => $line)
        {
              $indentCount = str_split($line);
              $iCount = 0;

              foreach($indentCount as $iKey => $iVal)
              {
                if($iVal == " ")
                {
                    $iCount++;
                }
                elseif($iVal == "    ")
                {
                    $iCount = $iCount + 4;
                }
                elseif($sVal != " " || $sVal != "    ")
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;

              if(is_null($prevIndent))
              {
                $prevIndent = $curIndent;
              } //prevent going into infinite recursion.

              if($prevIndent < $curIndent)
              {
                   $line = array_pop($block); //get last line, since it's indent level belongs to the parent block
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr;
              }

              else if($prevIndent > $curIndent )
              {
                   $tmp = explode("<explodeHere>", findBlockQuotes($code, $line)); //seperate the block from the next line of current indent level
                   $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
                   $block[] = $tmp[1]; //this is the extra line
               }

              else{
                   $block[] = trim($line); //get rid of indent, because you will nest blockquotes instead
              }
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$nestedBlocks = '<blockquote>'.findBlockQuotes($code).'<blockquote>';
echo $nestedBlocks;

?>

 

Result

<blockquote>
var = 'Test!';<explodeHere>{<blockquote>

 

At least it echoed something! :P

Link to comment
Share on other sites

oh bugger... here's the fix (well... a fix...):

 

function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.
        $block = array();
        $prevIndent = getLengthOf($firstStr); //change this line to whatever you need in order to get the length of $firstStr

 

and i think also:

 

              if(is_null($prevIndent))
              {
                $prevIndent = $curIndent;  //prevent going into infinite recursion.
              }
              else{
                $block[] = $firstStr; //for every recursion but the first, add $firstStr to the block, because it belongs here
              }

 

i'm sorry this is not functioning properly. i kinda made it up as i went along... i'm no good at planning my code on paper first  :P

Link to comment
Share on other sites

just to clarify, since i notice i didn't comment the conditions:

 

if($prevIndent < $curIndent) = if the current indent is longer than the previous indent. meaning, the current line-level is nested inside the previous line-level, so we have to make a recursive function call to deal with this nested block before we continue. like so:

 

this line is the previous line.

          this line is the current line.

 

 

else if($prevIndent > $curIndent ) = if the previous indent is longer than the current indent. meaning, the previous line-level is nested inside the current line-level, so we reached the end of a block - return the block and continue the parent block. like so:

 

                this line is the previous line.

this line is the current line

 

else = only option left is that the previous line and the current line are on the same level, so just stor the line in the array and continue the loop.

Link to comment
Share on other sites

Ok this is what it is now. Tell me if you see anything wrong with it, because all the function is doing is returning <explodeHere>

 

<?php

$code =
"var = 'Test!';
{
    if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";

function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.
        $block = array();
        
        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);
        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if($sVal == " ")
            {
                $sCount++;
            }
            elseif($sVal == "    ")
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

        $lineArray = explode("\n", $code);
        //while($line = fgets($fh)){

        foreach($lineArray as $key => $line)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($line);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if($iVal == " ")
                {
                    $iCount++;
                }
                elseif($iVal == "    ")
                {
                    $iCount = $iCount + 4;
                }
                elseif($iVal != " " || $iVal != "    ")
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;

              if(is_null($prevIndent))
              {
                $prevIndent = $curIndent;  //prevent going into infinite recursion.
              }
              else{
                $block[] = $firstStr; //for every recursion but the first, add $firstStr to the block, because it belongs here
              }
              
              if($prevIndent < $curIndent)
              {
                   //echo "prev < cur<br>";
                   $line = array_pop($block); //get last line, since it's indent level belongs to the parent block
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr;
              }

              else if($prevIndent > $curIndent )
              {
                   //echo "prev > cur<br>";
                   $tmp = explode("<explodeHere>", findBlockQuotes($code, $line)); //seperate the block from the next line of current indent level
                   $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
                   $block[] = $tmp[1]; //this is the extra line
               }

              else{
                //echo "same<br>";
                   $block[] = trim($line); //get rid of indent, because you will nest blockquotes instead
              }
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$nestedBlocks = '<blockquote>'.findBlockQuotes($code).'<blockquote>';
echo $nestedBlocks;

?>


Link to comment
Share on other sites

i changed changed some stuff that i'd missed. also, i changed your whitespace checks from literal spaces to the ascii value checks (becasue \t isn't supposed to be 4 spaces). sorry i'm not testing my stuff - i'm upgrading ubuntu to 8.10, and i only have a webserver set up on my windows install. once it finishes, i'll reboot into windows and run some tests.

 

<?php

$code =
"var = 'Test!';
{
    if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";

function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.
        $block = array();
        
        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);
        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if(ord($sVal) == 20) //check ascii value of " " instead of literal " "
            {
                $sCount++;
            }
            elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

        $lineArray = explode("\n", $code);
        //while($line = fgets($fh)){

        foreach($lineArray as $key => $line)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($line);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if(ord($sVal) == 20) //check ascii value of " " instead of literal " "
                {
                    $iCount++;
                }
                elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
                {
                    $iCount = $iCount + 4;
                }
                elseif(ord($iVal) != 20 || ord($iVal) != 9)
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;

              if(is_null($prevIndent))
              {
                $prevIndent = $curIndent;  //prevent going into infinite recursion.
              }
              else{
                $block[] = $firstStr; //for every recursion but the first, add $firstStr to the block, because it belongs here
              }
              
              if($prevIndent < $curIndent)
              {
                   //echo "prev < cur<br>";
                   $line = array_pop($block); //get last line, since it's indent level belongs to the parent block
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr;
              }

              else if($prevIndent > $curIndent )
              {
                   //echo "prev > cur<br>";
                   $tmp = explode("<explodeHere>", findBlockQuotes($code, $line)); //seperate the block from the next line of current indent level
                   $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
                   $block[] = $tmp[1]; //this is the extra line
               }

                //echo "same<br>";
                   //this should happen for both prev > cur and for prev == cur:
                   $block[] = trim($line); //get rid of indent, because you will nest blockquotes instead
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$nestedBlocks = '<blockquote>'.findBlockQuotes($code).'<blockquote>';
echo $nestedBlocks;

?>

Link to comment
Share on other sites

with the last version of the code i posted i'm getting the whole input echoed but there's a slight problem...

 

i'm not sure why, but something in the way your handling the input string is eliminating indentation on all lines (i'm echoing $prevIndent and $curIndent on each iteration/recursion and they are both set to 0 all the time). i will look at it more tomorrow. it's late and i'm going to bed.

 

Edit - this is not as a result of using ord(), since i reverted to your original checks for literal spaces, and got the same results.

Link to comment
Share on other sites

there are 2 reason2 i was getting those results last night:

- a small (enormous) flaw in the logic (i was calling recursion when i should have been returning and vice-versa).

- for some reason, the script was not the script was not recognizing literal spaces (in the if blocks where you find the indent), and when i changed those to use ord(), i got the ascii values wrong  :-\

 

it's still not working properly, but im making progress:

<blockquote>var = 'Test!'; {
       <blockquote>if(nest = true) if(nest = true) if(nest = true) { if(nest = true)
              <blockquote>indent; indent; indent;</blockquote>
         indent; if(nest = true)</blockquote>
if(nest = true) {
        <blockquote>indent; indent; indent;</blockquote>
indent;
</blockquote>

 

looks awful, but at least things are nesting now (which they didn't last night). i'll keep working on it and see what the hell i'm missing. here's the current code i'm working on. let me know if you manage to figure something out:

<?php

$code =
"var = 'Test!';
{
if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";
echo $code."<br />";
function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.

$block = array();
        
        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);

        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if(ord($sVal) == 32) //check ascii value of " " instead of literal " "
            {
                $sCount++;
            }
            elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

	$lineArray = array();
        
	$lineArray = explode("\n", $code);
        //while($line = fgets($fh)){

        foreach($lineArray as $key => $line)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($line);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if(ord($iVal) == 32) //check ascii value of " " instead of literal " "
                {
                    $iCount++;
                }
                elseif(ord($iVal) == 9) //check ascii value of \t instead of literal 4 spaces
                {
                    $iCount = $iCount + 4;
                }
                elseif(ord($iVal) != 32 || ord($iVal) != 9)
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;
        	 if (!is_null($firstStr))
                $block[] = trim($firstStr); //for every recursion but the first, add $firstStr to the block, because it belongs here
              
              if($prevIndent > $curIndent)
              {
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr;//."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr;
              }

              else if($prevIndent < $curIndent )
              {
               	echo "call recursion<br/>";
			$newArray = array_slice($lineArray, $key);
               	$code = implode("\n", $newArray);
                $block[] = '<blockquote>'.findBlockQuotes($code, $line).'</blockquote>'; //put the nested stuff in a blockquote
               }

               //for both $prevIndent < $curIndent and $prevIndent == $curIndent
               $block[] = trim($line); //get rid of indent, because you will nest blockquotes instead

			//save current indent level for next iteration
               $prevIndent = $curIndent;
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$nestedBlocks = '<blockquote>'.findBlockQuotes($code).'</blockquote>';
echo $nestedBlocks;

?>

Link to comment
Share on other sites

nearly solved it. it now prints everything and in the right nesting order. only problem is now duplication of data, which is half solved - i'm trying to figure out where i have an infinite loop. i'll try to get you a working version a little later - i have some stuff to do.

<?php

$code =
"var = 'Test!';
{
if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";
echo $code."<br />";
function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.

$block = array();
        
        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);

        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if(ord($sVal) == 32) //check ascii value of " " instead of literal " "
            {
                $sCount++;
            }
            elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

	$lineArray = array();
        
	$lineArray = explode("\n", $code);
        //while($line = fgets($fh)){
	$loopCount = count($lineArray);
        for($i = 0;$i < $loopCount; ++$i)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($lineArray[$i]);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if(ord($iVal) == 32) //check ascii value of " " instead of literal " "
                {
                    $iCount++;
                }
                elseif(ord($iVal) == 9) //check ascii value of \t instead of literal 4 spaces
                {
                    $iCount = $iCount + 4;
                }
                elseif(ord($iVal) != 32 || ord($iVal) != 9)
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;
        	 if (!is_null($firstStr))
                $block[] = trim($firstStr); //for every recursion but the first, add $firstStr to the block, because it belongs here
              
              if($prevIndent > $curIndent)
              {
                   $blockStr = implode("\n", $block); //put it all in a string and return it.
                   $returnStr = $blockStr;//."<explodeHere>".$line; //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr."<explodeHere>".$curIndent."<explodeHere>".$i;
              }

              else if($prevIndent < $curIndent )
              {
               	echo "call recursion<br/>";
			$newArray = array_slice($lineArray, $i);
               	$code = implode("\n", $newArray);
               	$tmp = explode("<explodeHere>", findBlockQuotes($code, $lineArray[$i]));
               	$prevIndent = $tmp[1]; //get the previous line indet from the recursion
               	$i = $tmp[2]; //skip all the lines already parsed in the recusrion
                $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
              	continue; 
              }

               else{//for both $prevIndent < $curIndent and $prevIndent == $curIndent
               $block[] = trim($lineArray[$i]); //get rid of indent, because you will nest blockquotes instead
               }
			//save current indent level for next iteration
               $prevIndent = $curIndent;
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$retuenStr = explode("!explodeHere!", findBlockQuotes($code));
$nestedBlocks = '<blockquote>'.$retuenStr[0].'</blockquote>';
echo $nestedBlocks;

?>

 

this is what i'm working with right now. it has the infinite loop problem, so it won't print anything useful to screen.

not everything is properly commented at the moment. sorry. i'll make sure to fix that for the final version.

Link to comment
Share on other sites

ok. the infinite loop is fixed by changing this:

$i = $tmp[2]; //skip all the lines already parsed in the recusrion

 

to this:

$i += $tmp[2]; //skip all the lines already parsed in the recusrion

 

but, it still doesn't work properly. you can see the best results i can get so far by commenting out that line (the one you just changed to fix the loop). i'll keep working on it.

Link to comment
Share on other sites

nearly there:

<?php

$code =
"var = 'Test!';
{
if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";
echo $code."<br />";
function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.

$block = array();
        
        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);

        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if(ord($sVal) == 32) //check ascii value of " " instead of literal " "
            {
                $sCount++;
            }
            elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

	$lineArray = array();
        
	$lineArray = explode("\n", $code);
        //while($line = fgets($fh)){
	$loopCount = count($lineArray);
        for($i = 0; $i < $loopCount; ++$i)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($lineArray[$i]);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if(ord($iVal) == 32) //check ascii value of " " instead of literal " "
                {
                    $iCount++;
                }
                elseif(ord($iVal) == 9) //check ascii value of \t instead of literal 4 spaces
                {
                    $iCount = $iCount + 4;
                }
                elseif(ord($iVal) != 32 || ord($iVal) != 9)
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;
        	 if (!is_null($firstStr)){
                $block[] = trim($firstStr); //for every recursion but the first, add $firstStr to the block, because it belongs here
        	 }
        	else{// to get the first line from $code
               $block[] = trim($lineArray[$i]); //get rid of indent, because you will nest blockquotes instead
              }
              
              if($prevIndent > $curIndent)
              {
              	//echo "call return ";
                   $returnStr = implode("\n", $block); //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr."<explodeHere>".$curIndent."<explodeHere>".$i;
              }

              else if($prevIndent < $curIndent )
              {
               	//echo "call recursion ";
			$newArray = array_slice($lineArray, $i);
               	$code = implode("\n", $newArray);
               	$tmp = explode("<explodeHere>", findBlockQuotes($code, $lineArray[$i]));
               	$prevIndent = $tmp[1]; //get the previous line indet from the recursion
               	$i += $tmp[2] - 1; //skip all the lines already parsed in the recusrion
                $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
              	//continue; 
              }
              
			//save current indent level for next iteration
               $prevIndent = $curIndent;
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$retuenStr = explode("<explodeHere>", findBlockQuotes($code));
$nestedBlocks = '<blockquote>'.$retuenStr[0].'</blockquote>';
echo $nestedBlocks;

?>

 

there's some mess up with the amount of times the script loops due to setting $prevIndent to the last line indet of the child block:

$prevIndent = $tmp[1]; //get the previous line indnet from the recursion

(line 89)

 

and then resetting it to $curIndent on line 96, which holds the indent value of the last line before entering the afore-mentioned child block. the reason i left this the way it is for now, is that something in the returning of the last indent of the child block (line 80, after first explode tag) is wrong, and the output gets all messed up if i use that value as the parent's $prevIndent (to see this in action put line 96 inside an else{} block).

 

god this is a mess... i hope you can make sense of this - i find it a little difficult to explain.

 

the reason we're having so much trouble is that i wrote this function for using with a file handle, which would walk through the file automatically, and we're trying to make it work for a string and we have to walk the string manually, which is giving me trouble for some reason.

 

the answer to this should be in playing around with the $prevIndent and $curIndet i think. as usual, if you find something, please let me know.

Link to comment
Share on other sites

small update to bring us even closer - i found the relooping problem - i put

if (!is_null($firstStr)){
	$block[] = trim($firstStr); //for every recursion but the first, add $firstStr to the block, because it belongs here
}

inside the for loop.  :-\ rather silly of me.

 

the last (i think) problem has something to do with the line walking. the recursive call returns only 1 "oudent;", but something in the code appends another copy to the previous $block[] element for some reason. add a print_r($tmp) on line 91 and an echo at the head of line 81 to see what i mean.

 

here's the current code:

<?php

$code =
"var = 'Test!';
{
if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";
echo $code."<br />";
function findBlockQuotes($code, $firstStr = NULL){ //$firstStr holds the first string of each block. you'll see y.

$block = array();

if (!is_null($firstStr)){
	$block[] = trim($firstStr); //for every recursion but the first, add $firstStr to the block, because it belongs here
}        

        /** Break the line into an array and look for the first non-whitespace character */
        $firstStrLen = str_split($firstStr);

        $sCount = (int)0;
        foreach($firstStrLen as $skey => $sVal)
        {
            if(ord($sVal) == 32) //check ascii value of " " instead of literal " "
            {
                $sCount++;
            }
            elseif(ord($sVal) == 9) //check ascii value of \t instead of literal 4 spaces
            {
                $sCount = $sCount + 4;
            }
            else
            {
                break;
            }
        }
        
        $prevIndent = $sCount; //change this line to whatever you need in order to get the length of $firstStr

	$lineArray = array();
        
	$lineArray = explode("\n", $code);
        //while($line = fgets($fh)){
	$loopCount = count($lineArray);
        for($i = 0; $i < $loopCount; ++$i)
        {
              /** Break the line into an array and look for the first non-whitespace character */
              $indentCount = str_split($lineArray[$i]);
              $iCount = (int)0;
              foreach($indentCount as $iKey => $iVal)
              {
                if(ord($iVal) == 32) //check ascii value of " " instead of literal " "
                {
                    $iCount++;
                }
                elseif(ord($iVal) == 9) //check ascii value of \t instead of literal 4 spaces
                {
                    $iCount = $iCount + 4;
                }
                elseif(ord($iVal) != 32 || ord($iVal) != 9)
                {
                    break;
                }
              }

              $curIndent = $iCount; //get the length of the current indent;

              if (is_null($firstStr)){// to get the first line from $code
               $block[] = trim($lineArray[$i]); //get rid of indent, because you will nest blockquotes instead
              }
              
              if($prevIndent > $curIndent)
              {
              	//echo "call return ";
                   $returnStr = implode("\n", $block); //append $line onto $blockStr so it can be returned, but add an easy-to-find explode indicator
                   return $returnStr."<explodeHere>".$curIndent."<explodeHere>".$i;
              }

              else if($prevIndent < $curIndent )
              {
               	//echo "call recursion ";
			$newArray = array_slice($lineArray, $i);
               	$code = implode("\n", $newArray);
                $tmp = explode("<explodeHere>", findBlockQuotes($code, $lineArray[$i]));
                //$prevIndent = $tmp[1]; //get the previous line indet from the recursion
               	$i += $tmp[2] - 1; //skip all the lines already parsed in the recusrion
                $block[] = '<blockquote>'.$tmp[0].'</blockquote>'; //put the nested stuff in a blockquote
              	//continue; 
              }
              
			//save current indent level for next iteration
               $prevIndent = $curIndent;
        }
        return implode("\n", $block); //when the file runs out of lines, return the stuff
}

//call the function
$retuenStr = explode("<explodeHere>", findBlockQuotes($code));
$nestedBlocks = '<blockquote>'.$retuenStr[0].'</blockquote>';
echo $nestedBlocks;
?>

Link to comment
Share on other sites

ok, i got sick of wasting both your and my time debugging recursive logic, and i made a new one from scratch. this one works.  ;D

 

behold, nestBlocks() v.2:

<?php 

function nestBlocks($code, $lineNum = 0){

$block = array("<blockquote>"); //array to hold the blocked text. will be imploded around \n at the end
$linesArray = explode("\n", $code); //turn the text into an array by lines.

$prevIndent = 0;
$chr = 0;
while (1){ //find indent of first line
	if (ord($linesArray[$lineNum][$chr]) == 32){
		++$prevIndent; //add 1 to indent for space character.
		++$chr; //move to next character in line
	}
	else if (ord($linesArray[$lineNum][$chr]) == 9){
		$prevIndent += 4; //add 4 to indent for tab character.
		++$chr; //move to next character in line
	}
	else break; //break the loop on first non-whitespace character.
}

//walk linesArray. don't increment $i, as it gets incremented by different valies by different
// conditions in the loop.
$loopCount = count($linesArray);
for($i = $lineNum; $i < $loopCount; ){

	$curIndent = 0;
	$chr = 0;
	while (1){ //find indent of currentt line
		if (ord($linesArray[$i][$chr]) == 32){
			++$curIndent; //add 1 to indent for space character.
			++$chr; //move to next character in line
		}
		else if (ord($linesArray[$i][$chr]) == 9){
			$curIndent += 4; //add 4 to indent for tab character.
			++$chr; //move to next character in line
		}
		else break; //break the loop on first non-whitespace character.
	}

	if ($curIndent < $prevIndent){//reached the end of block. close the block and return it as a string
		$block[] = "</blockquote>"; //close the block
		$returnStr = implode("\n", $block);
		$returnStr .= "<explode>".$i; //append the current line number to the parent function
		return $returnStr;
	}
	else if ($curIndent > $prevIndent){//reached a new block. call a recursion and save the returned txt.
		$result = explode("<explode>", nestBlocks($code, $i)); //get nested block
		$block[] = trim($result[0]); //save nested block
		$i = $result[1]; //set new current line
	}
	else{ //same indent. save the line, and loop.
		$block[] = trim($linesArray[$i]);
		$prevIndent = $curIndent; //save current indent for next iteration
		++$i;
	}
}

$block[] = "</blockquote>"; //close block before return
$returnStr = implode("\n", $block); //convert to string
return $returnStr;
}

$code =
"var = 'Test!';
{
if(nest = true)
    {
        indent;
    }
    else
    {
        outdent;
    }
}";

$blockedText = nestBlocks($code);
echo $blockedText;
?>

 

please note that the output to your browser won't show the line breaks, as browsers ignore "\n" characters. i didn't implode the blocks around <br> tags, since you said you can't use html. i don't know if \n works in bbcode, but be sure to change \n in the implode() functions (lines 43, 60) to whatever does cause a newline.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.