"While" or "strpos" is not working for me

Hi everyone,
I’d like to show on screen the positions of string ‘is’ within string ‘is is is’.
I use the following code:

<?php
$sentence='is is is';
$search='is';
$length=strlen($search);
$offset=0;
$j=1;
while (strpos($sentence,$search,$offset));
{
 echo $j.'. '.strpos($sentence,$search,$offset).'<br>';
 $offset += $length;
 $j++;
}

?>

All I get on string is:

  1. 0
    which means: “while” loop operated once only. Why didn’t it continue to other ‘is’ appearances in the string?
    Thanks

your while() loop is not operating at all. your strpos() call returns 0, which is treated as false and thus the loop doesn’t start. but since you terminated the while(); with a semi-colon, the loop is empty to begin with. you code block in braces after that just stands on its own and hence runs once.

1 Like

There’s a few things wrong with your script. The first (and most obvious) is that you’ve put a semi-colon (signifying an empty statement) at the end of you WHILE loop condition. This means it will continue to execute until the condition is false. Fortunately for you, it will be false on the first time round (I’ll explain why in a second). That is why the code in-between the braces outputs once.

So we now have the following (semicolon omitted):

<?php
$sentence='is is is';
$search='is';
$length=strlen($search);
$offset=0;
$j=1;
while (strpos($sentence,$search,$offset))
{
 echo $j.'. '.strpos($sentence,$search,$offset).'<br>';
 $offset += $length;
 $j++;
}

As the above code stands, the body will not execute at all now. Why? Because if you have a look at the manual, the strpos() function returns FALSE if no match is found, or the offset (as an integer) if one is found. BUT what you have to remember is that indexes start at 0, and right now the offset of your first match will return 0 - and 0 in PHP is a falsey value (see here for other falsey values). This means that the condition for your WHILE loop actually evaluates to false, thus not executing the body of you loop.

So let’s fix that by using a strict comparison and also remove some repetition by performing an assignment in your WHILE’s condition to be used throughout the WHILE body:

<?php

$sentence='is is is';
$search='is';
$length=strlen($search);
$offset=0;
$j=1;
while(($pos = strpos($sentence,$search,$offset)) !== FALSE)
{
 echo $j.'. '.$pos.'<br>';
 $offset += $length;
 $j++;
}

The above will now output:

1. 0
2. 3
3. 6
4. 6

So where’s the fourth result coming from? It’s coming from the fact that your $offset value is being calculated incorrectly. Upon each execution of the WHILE loop body, you’re simply adding on the length of the string to find. So what if a match is found at offset 5 of that string on the initial loop? The loop body will execute, adding on (in your case above) 2 to the offset, and so your strpos function will start searching at offset 2 next time. When searching from offset 2, it will again find the same match (at offset 5 last time), but this time it will be at an offset of 3. Your code will also find the same match again the next iteration too. So in order to calculate the correct offset, you must add the $pos variable onto it as well:

$sentence='is is is';
$search='is';
$length=strlen($search);
$offset=0;
$j=1;
while(($pos = strpos($sentence,$search,$offset)) !== FALSE)
{
 echo $j.'. '.$pos.'<br>';
 $offset = $pos + $length;
 $j++;
}

The above should now output:

1. 0
2. 3
3. 6

EDIT: @Dormilich beat me to the initial problems your script was facing - though my reply continues to explain what else was wrong with it.

4 Likes

Thanks a lot (and a lot to learn from your post),
I will sit and learn what you wrote because I didn’t grasp it instantly (except of the semicolon in “while”).
Thanks again.

Hi,
First line of output shows:

  1. 0
    which means: first while’s expression result is “0” which is false !
    So how comes the code within the while expression was operated all the same?!!
    Thanks

It was because your WHILE loop did not have a body. You accidentally put a semicolon at the end of your while loop:

while (strpos($sentence,$search,$offset));

This meant that the condition of the while loop executed only (and fortunately for you, the first return value of the condition was 0 (falsey) making it exit straight away). You then have a body of code that is not tied to any construct:

{
 echo $j.'. '.strpos($sentence,$search,$offset).'<br>';
 $offset += $length;
 $j++;
}

In other languages (like Java), it’s called an anonymous code block and is used to restrict variable scope, however PHP does not have any such feature but it is still considered valid code.