search for in the  
<substr_comparesubstr_replace>
Last updated: Thu, 19 May 2005

substr_count

(PHP 4, PHP 5)

substr_count -- Count the number of substring occurrences

Description

int substr_count ( string haystack, string needle )

substr_count() returns the number of times the needle substring occurs in the haystack string. Please note that needle is case sensitive.

Example 1. substr_count() example

<?php
echo substr_count("This is a test", "is"); // prints out 2
?>

See also count_chars(), strpos(), substr(), and strstr().



User Contributed Notes
substr_count
jsb17 at cornell dot edu
03-Oct-2004 06:42
In response to Jesse at bend dot com's comment regarding case insensitivity, if your substr_count() function is in a loop, never implement this:

<?php
  
//  for each needle
  
for($i=0; $<$n_needles; $i++){
      
//  duplicating strtolower() process time on each iteration! OUCH!
      
substr_count(strtolower($haystack), strtolower($needle[$i]));
   } 
//  for each needle
?>

I recommend implementing this instead:

<?php
  
//  initiate lowercase instances of search text and needles
  
$haystack_lower = strtolower($haystack);
   for (
$i=0; $<$n_needles; $i++){$needle[$i] = strtolower($needle[$i]);}  //  after exploding
   //  for each needle
  
for($i=0; $i<$n_needles; $i++){
      
substr_count($haystack_lower, $needle[$i]);  //  assign this to whatever...
  
//  for each needle
?>

An example of the aforementioned arises if you are implementing, for instance, a search function in a help manual, when you check each user-entered search word against the manual text (like at the top of this page), and count the number of occurrences of each search word to weigh your results so you can display the best results first.

If the above code is within ANOTHER loop traversing each of many manual pages, then you'll definitely get hammered on the iterative strtolower() process time.  Always try to keep strtolower() outside the outermost loop, and query using use "SELECT LOWER(manual_text) FROM..." instead.

Maybe this comment belongs in the strtolower() documentation?
McAjvar
03-Sep-2004 05:15
this is a small correction of bpotter's code:

if (substr_count($QUERY_STRING, '&amp;') > 0) {
     $QUERY_STRING = str_replace('&amp;', '&', $QUERY_STRING);
     $queryArray = explode('&',$QUERY_STRING);
     foreach ($queryArray as $queryItem) {
         $querySegment = explode("=",$queryItem,2);
         list ($key, $val) = $querySegment ;
         if ($val)
               $$key = $val;
     }
}

explanation: these corrections do not replace
file.php?var1=using winamp; others suck&amp;var2=1+1=2&amp;var3=mongolia

into
file.php?var1=using win others suck&var2=1+1=2&var3=mongolia

but rather into
file.php?var1=using winamp; others suck&var2=1+1=2&var3=mongolia

also, the when having values which also contain '=', the parameter 2 in explode () prevents it into splitting it in more than 2 values. so $var2 isn't an array ('1+1', '2') but rather has the value '1+1=2'

hope this helps :)
XinfoX X at X XkarlX X-X XphilippX X dot X XdeX
21-Dec-2003 03:27
Yet another reference to the "cgcgcgcgcgcgc" example posted by "chris at pecoraro dot net":

Your request can be fulfilled with the Perl compatible regular expressions and their lookahead and lookbehind features.

The example

 $number_of_full_pattern = preg_match_all('/(cgc)/', "cgcgcgcgcgcgcg", $chunks);

works like the substr_count function. The variable $number_of_full_pattern has the value 3, because the default behavior of Perl compatible regular expressions is to consume the characters of the string subject that were matched by the (sub)pattern. That is, the pointer will be moved to the end of the matched substring.
But we can use the lookahead feature that disables the moving of the pointer:

 $number_of_full_pattern = preg_match_all('/(cg(?=c))/', "cgcgcgcgcgcgcg", $chunks);

In this case the variable $number_of_full_pattern has the value 6.
Firstly a string "cg" will be matched and the pointer will be moved to the end of this string. Then the regular expression looks ahead whether a 'c' can be matched. Despite of the occurence of the character 'c' the pointer is not moved.
bishop
03-Dec-2003 06:42
Here is a simple item frequency counter function, useful in reporting or statistical apps:

<?php
function count_item(&$freq, $item, $inc = 1) {
   if (!
is_array($freq)) {
      
$freq = array ();
   }
  
$freq[$item] = (isset($freq[$item]) ? ($freq[$item] += $inc) : $inc);

   return
true;
}
?>

This function saves you the hassle of doing the isset() check each time you wish to increase the frequency. If you're not normally concerned over PHP's warnings about uninitialized variables, then you should probably start from the beginning. If you are, use the function above like:

<?php
count_item
($freq, 'foo');
count_item($freq, 'bar');
count_item($freq, 'foo');
?>

After this, $freq will equal array ('foo' => 2, 'bar' => 1)
W Chee Wee
21-Jun-2003 01:18
With reference to the "cgcgcgcgcgcgc" example, u can treat the string as a queue and just pop out the first character in iterations. You will get a return value of 6, thus allowing for overlapping.
Big daddy Programming
02-Apr-2003 11:16
3 is right. It should not return 6. If it is starting from left to right it sees "cgc" then the next character is a "g" so that character is skipped. So the next occurence happens on the next "cgc". As you can see this only happens 3 times. Now you can get 6 if after the first "cgc" you back up a character.
chris at pecoraro dot net
27-Mar-2003 01:24
this function also doesn't work well if you have "cgcgcgcgcgcgcg" as a search string and you want to count occurences of "cgc"

it returns "3", whereas it SHOULD return "6", assuming we allow "overlapping". Maybe there should be an "allow overlap" optional parameter.

-cjp
bpotter at statelinecasinos dot com
07-Sep-2002 08:11
This is useful for pages that depend on the QUERY_STRING for values.  Some search Engines (AOL) use &amp; in the link, which can cause problems and/or wrong information to be displayed.

if (substr_count($QUERY_STRING, "amp;") > 0) {
     $QUERY_STRING = str_replace("amp;", "", $QUERY_STRING);
     $queryArray = explode("&",$QUERY_STRING);
     foreach ($queryArray as $queryItem) {
         $querySegment = explode("=",$queryItem);
         list ($key, $val) = $querySegment ;
         if ($val)
               $$key = $val;
     }
}

Hope this helps.
Jesse at bend dot com
08-Jan-2001 09:58
I am not certain why the above fellah is worried about case sensitivity, ereg functions are mighty slow.. and if you need a case insensitive count, try this:

substr_count(strtolower($haystack), strtolower($needle))

<substr_comparesubstr_replace>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 17:35:34 2005 CDT