Connecting Tech Pros Worldwide Help | Site Map

Problem creating while Loop listing each occurance of a number in a string

Member
 
Join Date: Sep 2007
Posts: 52
#1: Sep 23 '08
Hi,

I created a while-loop which will basically go through each number in a string and list the positions of the desired number.

For example suppose I have a string sa "12123124" and I want to list all the positions of "1" the output should be 0, 2 and 5.

My work out below is:
Expand|Select|Wrap|Line Numbers
  1. <html>
  2.     <body>
  3.         <?php
  4.             $number = "12123124";
  5.             $posFirst = 0; // Computer counts from 0.
  6.             $posLast = strlen($number)-1; // Since we are counting from 0, we need to 
  7.                                           // adjust the last position accordingly
  8.  
  9.             While($posFirst <= $posLast)
  10.             {
  11.                 $posFirst = strpos($number, "1", $posFirst);
  12.                 echo $posFirst."<p>";
  13.                 $posFirst = $posFirst+1;
  14.  
  15.  
  16.             }
  17.  
  18.         ?>
  19.     </body>
  20.  
  21. </html>
  22.  
The output I get is an infinite loop and I don't get what's causing it to loop forever.

0

2

5

2

5

2

5

2

5

2

5

2

Any idea would be appreciated. Thanks.
Dormilich's Avatar
Moderator
 
Join Date: Aug 2008
Location: Leipzig, Germany
Posts: 3,642
#2: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


It's the last cycle. In the incrementation $posFirst (which is at that moment: false) is set to 1 (false +1 = 1), you could either break out (if (is_boolean($posFirst)) break;) or use preg_match_all() with the PREG_OFFSET_CAPTURE flag instead of the while loop.

regards
Member
 
Join Date: Sep 2007
Posts: 52
#3: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Dormilich

It's the last cycle. In the incrementation $posFirst (which is at that moment: false) is set to 1 (false +1 = 1)

I didn't get it. The increment in line 13 merely increments the value. So $posFirst was initialised to 0 then it became 1 after first run. Why is it false + 1 = 1?
Atli's Avatar
Moderator
 
Join Date: Nov 2006
Location: Iceland
Posts: 3,746
#4: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Yea. The problem is that if the strpos function doesn't find a match, it returns false. Which PHP will convert into 1 when you try to compare it with another integer.

If I were doing this, I would simply check if the return value of that function was false.
Like:
Expand|Select|Wrap|Line Numbers
  1. $position = -1;
  2. while($position = strpos($heystack, $needle, $position + 1))
  3. {
  4.   echo "Found at $position<br />";
  5. }
  6.  
Dormilich's Avatar
Moderator
 
Join Date: Aug 2008
Location: Leipzig, Germany
Posts: 3,642
#5: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Atli

If I were doing this, I would simply check if the return value of that function was false.

definitely more elegant than my solution.... *sigh*
Member
 
Join Date: Sep 2007
Posts: 52
#6: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Atli

Yea. The problem is that if the strpos function doesn't find a match, it returns false. Which PHP will convert into 1 when you try to compare it with another integer.

If I were doing this, I would simply check if the return value of that function was false.
Like:

Expand|Select|Wrap|Line Numbers
  1. $position = -1;
  2. while($position = strpos($heystack, $needle, $position + 1))
  3. {
  4.   echo "Found at $position<br />";
  5. }
  6.  

Ok so, you intially set the value of $position to -1.

In the first run you are searching from position 0 ($position + 1, so -1 +1 = 0) and it found a value and prints it.

I am kind of lost what happens in the second pass through the while loop. Because you are not using condition checking == just =. So how does the computer know when to break off?

I get how you say it returns a false like that php link in your post says
Returns the position as an integer. If needle is not found, strpos() will return boolean FALSE.
Member
 
Join Date: Sep 2007
Posts: 52
#7: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Actually sorry guys ignore me.

I forgot that a variable in PHP can take different values like $var can be set to take string when you say

$var = "hello";

but later becomes a boolean if you say $var = FALSE or something like that. So after strpos() finishes searching the string it returns a boolean false. So the $position in the while loop of Atli's code becomes a boolean (false more specifically) and hence it breaks out.

I couldn't get how it was set to take string earlier and now taking boolean FALSE all of a sudden. Blame it on too much C coding.

Thanks for your help Atli & Dormilich.
Newbie
 
Join Date: Sep 2008
Location: Washington DC
Posts: 25
#8: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


I thought this was an interesting problem, and I played with it some.

First I added an "echo" at the beginning of the loop:
Expand|Select|Wrap|Line Numbers
  1. while($posFirst <= $posLast) {
  2.    echo $posFirst."-->";   //$posFirst value before the call to strpos()
  3.    $posFirst = strpos($number, "1", $posFirst);
  4.    echo $posFirst."<p>\n";   //$posFirst value AFTER the call
  5. }
  6.  
and got this output:
0-->0<p>1-->2<p>3-->5<p>6--><p>1-->2<p>3-->5<p>6--><p>1-->2<p>
which displays in browser as:
0-->0
1-->2
3-->5
6-->
1-->2
3-->5
6-->
1-->2
So, calling strpos with 0 returns 0. Adding 1 gives you 1.
2nd time in the loop: calling strpos with 1 returns 2. Adding 1 gives you 3.
3rd time in the loop: calling strpos with 3 returns 5. Adding 1 gives you 6.
4th time in the loop. calling strpos with 6 returns false. Adding 1 gives you 1 !!!
5th time in the loop: calling strpos with 1 returns 2. Adding 1 gives you 3.
and so on...

I was wondering if ++ acts differently, and it does! Replacing the last line in the loop with:
$posFirst++;
gives the following output:
0-->0
1-->2
3-->5
6-->
-->0
1-->2
So, using ++ operator on false yields false, but adding 1 to false makes a 1.
Atli's Avatar
Moderator
 
Join Date: Nov 2006
Location: Iceland
Posts: 3,746
#9: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


There is a bug in my previous code! (Hard to believe... I know :P)
But first, let me explain.

In a conditional statement, like a while or a if statement, PHP will look for a TRUE value, which is basically the same as comparing everything inside the while with TRUE.

So:
Expand|Select|Wrap|Line Numbers
  1. // This:
  2. while(true)
  3. // Is exactly like doing
  4. while(true == true)
  5.  
  6. // And this
  7. while(strpos($h, $n))
  8. // Is exactly like
  9. while(strpos($h, $n) == true)
  10.  
And, being both very smart and a bit annoying, PHP will consider any number above 0 and any non-empty string to be TRUE, but evaluating NULL, 0 and "" as FALSE.

So, strpost, returning a number when it finds a match and FALSE when it doesn't, will be considered TRUE when it finds a match...

With one exception (which is what I overlooked in my previous code).
When it finds a match at the first index (0), it returns 0, which will be evaluated as FALSE, ending the loop prematurely.

So to fix that, we just look for a boolean value rather than FALSE.
Like:
Expand|Select|Wrap|Line Numbers
  1. $position = -1;
  2. while(!is_bool($position = strpos($heystack, $needle, $position + 1)))
  3. {
  4.     echo "Found at $position<br />";
  5. }
  6.  
Sorry about that. Was eating when I wrote my first post :P
Member
 
Join Date: Sep 2007
Posts: 52
#10: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Atli

And, being both very smart and a bit annoying, PHP will consider any number above 0 and any non-empty string to be TRUE, but evaluating NULL, 0 and "" as FALSE.

Yeah it did terminate after printing zero but I thought there was something wrong with my syntax in while loop which is causing it to terminate at 0. Thanks for clarifying.
Member
 
Join Date: Sep 2007
Posts: 52
#11: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


that code works fine. Had a little trouble getting my head around that is_bool() becuase at first it looked like this:

is_bool(FALSE) is TRUE but digging a little deeper, is_bool looks at the type of variable not the content of the variable.

For a first timer dealing with is_bool() function it can be a little tricky! Kind of like a brain teaser.
Dormilich's Avatar
Moderator
 
Join Date: Aug 2008
Location: Leipzig, Germany
Posts: 3,642
#12: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Alien

What happens when strpos returns a FALSE after finishing searching the string for $needle? Because logically when it $position will then be FALSE and

!is_bool(FALSE) is same as TRUE and hence it'll dig again into the loop.

er no, is_bool() checks for a boolean type, so both true and false return true as result, which is negated and therefore it breaks the loop.

regards
Atli's Avatar
Moderator
 
Join Date: Nov 2006
Location: Iceland
Posts: 3,746
#13: Sep 23 '08

re: Problem creating while Loop listing each occurance of a number in a string


Quote:

Originally Posted by Alien

that code works fine. Had a little trouble getting my head around that is_bool() becuase at first it looked like this:

is_bool(FALSE) is TRUE but digging a little deeper, is_bool looks at the type of variable not the content of the variable.

Yea I can see why it could be confusing at first :)
It's in a series of "is_*" functions that check for all sorts of variable types.

Can be a little difficult to use cause PHP is so good at converting the types for you.
Like using is_int() to check numbers from user input will not work, because user input is always a string. But using numbers from user input in math works fine because PHP just converts it when it needs to.

It's very smart, but potentially very annoying :)
Reply