Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 11 of 11
  1. #1
    New Coder
    Join Date
    May 2012
    Posts
    89
    Thanks
    51
    Thanked 0 Times in 0 Posts

    Can someone see the error in my logic?

    Gidday

    I'm making a basic keyword highlighter:

    Code:
            $string = "Here be my string la";
    
             //trim up keywords, and put them into $words array ...
    	$term = preg_replace('/(\s+)/i', ' ', trim("la"));		
    	$words = explode(' ', $term);
    	
    	$highlighted = array();
    	
    	foreach ( $words as $word ){
    		$highlighted[] = "<span class='H'>".ucwords(htmlentities($word, ENT_NOQUOTES, 'UTF-8'))."</span>";			
    	}
    	
    	//replace any hits with the highlighted version...
    
    	return  str_ireplace($words, $highlighted, $string);
    It works fine, except if your keyword resembles anything in span class='H' eg 'la'

    I understand that it's finding 'la' within the span, and then putting a span around it. What I don't understand is HOW? I figure I'm misunderstanding str_ireplace, but doesn't it say 'if $words[0] is in "string", replace it with $highlighted[0]', and so on through the arrays. How is it finding 'la' in
    Code:
    <span class='H'>".ucwords(htmlentities($word, ENT_NOQUOTES, 'UTF-8'))."</span>
    ?

    Thanks guys
    Last edited by shaunthomson; 12-07-2012 at 03:48 PM.

  • #2
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    str[i]_replace are greedy in regards to an array. So it will take the string in its entirety, and check for replacements on EACH iteration of item provided by the array needle.
    So if I do like so:
    PHP Code:
    $aWords = array('cat''dog''mouse''la');
    $aHighlight = array();
    $str 'The dog chases the cat which chases the mouse';

    foreach (
    $aWords AS $word)
    {
        
    $aHighlight[] = sprintf('<span class="H">%s</span>'ucwords($word));
    }

    print 
    str_ireplace($aWords$aHighlight$str); 
    The results would be in sequence:
    Code:
    The dog chases the cat which chases the mouse <-- evaluate 'cat'
    The dog chases the <span class="H">Cat</span> which chases the mouse <-- evaluate 'dog'
    The <span class="H">Dog</span> chases the <span class="H">Cat</span> which chases the mouse <-- evaluate 'mouse'
    The <span class="H">Dog</span> chases the <span class="H">Cat</span> which chases the <span class="H">Mouse</span> <-- evaluate 'la'
    The <span c<span class="H">La</span>ss="H">Dog</span> chases the <span c<span class="H">La</span>ss="H">Cat</span> which chases the <span class="H">La</span> <span c<span class="H">La</span>ss="H">Mouse</span> <-- end result
    Because of the purpose of the above, there isn't really a great way to do this with an string match/replace technique (you'll need to keep backtracking and checking new terms).

    Instead, simply use pattern matching.
    PHP Code:
    $str 'The dog chases the cat which chases the mouse';

    $aWords = array('cat''dog''mouse''la');
    array_walk($aWordscreate_function('&$s''$s = preg_quote($s, "/");'));
    $sPattern '/(' implode('|'$aWords) . ')/i';

    print 
    preg_replace_callback($sPattern,
        
    create_function(
            
    '$s'
            
    'return sprintf(\'<span class="H">%s</span>\', ucwords($s[0]));'
            
    ),
        
    $str
        
    ); 
    Try that.

  • Users who have thanked Fou-Lu for this post:

    shaunthomson (12-07-2012)

  • #3
    New Coder
    Join Date
    May 2012
    Posts
    89
    Thanks
    51
    Thanked 0 Times in 0 Posts
    Thanks Fou - I thought I was going nuts. Your explanation and alternative are much appreciated.

  • #4
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Yep you bet. Also, you can check the API here; I didn't realize that they did actually indicate that this would happen (check the caution note just before the user comments): http://ca2.php.net/manual/en/function.str-replace.php

  • #5
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    I did this in a slightly different way and don't know if the following code is of any interest - apologies if not.

    PHP Code:
    function onlyWholeWords(&$value$key) {
        
    // Ignores words after // comment delimiters.
        //$value = "/\b(" . $value . ")\b/";    // doesn't handle comments, so..
        //$value = "/^(?:(?!\/\/).)*\K\b(" . $value . ")\b/"; 
        // \K lookbehind alternative is not supported in PHP < 5.2.4, so use:
        
    $value "/^((?:(?!\/\/).)*)\b" $value "\b/";
    }
    function 
    addSpan(&$value$key$color='blue') {
        
    $value "$1<span style='color:$color'>" $value "</span>";
    }
    function 
    codeWords($code) {
        
    $keywords = array('as''break''case''class''continue''default'
            
    'do''elif''else''elseif''for''foreach''function''if'
            
    'new''null''return''self''switch''this''to''typeof'
            
    'until''var''void''while''with');
        
    $keywords2 $keywords;

        
    array_walk($keywords'onlyWholeWords');
        
    array_walk($keywords2'addSpan''blue');
        
    $code preg_replace($keywords$keywords2$code);
        return 
    $code;

    It might be of interest because it uses functions and it can be modified to use different colours for different (arrays of) words:

    PHP Code:
    function codeWords($code$colour)
    // ...
        
    array_walk($keywords2'addSpan'$colour); 
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • #6
    rgb
    rgb is offline
    New Coder
    Join Date
    Jul 2011
    Posts
    17
    Thanks
    0
    Thanked 2 Times in 2 Posts
    As a newcomer I'm learning a lot from this forum and I've been playing with some of the suggestions on this topic.
    Wouldn't something simple like this do the job? Playing with Fou-Lou's latter example I notice that substituting 'concatenation' for 'cat' in $str echos out as "conCatenation". This simple version fixes that and also allows for punctuation to be appended to a keyword.

    Code:
    echo "<style>.H{color:red;}</style>";
     	$str = 'The dog chases the cat, which chases the mouse.';
    	$aWords = array('cat', 'dog', 'mouse', 'la');
    
    	$str = explode(' ',$str);
    	foreach($str as $word){
    		$remove = array(',', ';', '.'); // ignore common bits of puntuation
    		$trimmedword = strtolower(str_replace($remove, '', $word));// in case key words are upper case or capitalised
    		if(in_array($trimmedword,$aWords)){
    			echo "<span class=H>".ucwords($word)."</span>";
    			}
    			else {
    				echo $word;
    			}
    			echo "&nbsp;";
    		}
    Is this too simple? Am I missing something?
    Last edited by rgb; 12-08-2012 at 03:10 PM.

  • #7
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Quote Originally Posted by rgb View Post
    As a newcomer I'm learning a lot from this forum and I've been playing with some of the suggestions on this topic.
    Wouldn't something simple like this do the job? Playing with Fou-Lou's latter example I notice that substituting 'concatenation' for 'cat' in $str echos out as "conCatenation". This simple version fixes that and also allows for punctuation to be appended to a keyword.

    Code:
    echo "<style>.H{color:red;}</style>";
     	$str = 'The dog chases the cat, which chases the mouse.';
    	$aWords = array('cat', 'dog', 'mouse', 'la');
    
    	$str = explode(' ',$str);
    	foreach($str as $word){
    		$remove = array(',', ';', '.'); // ignore common bits of puntuation
    		$trimmedword = strtolower(str_replace($remove, '', $word));// in case key words are upper case or capitalised
    		if(in_array($trimmedword,$aWords)){
    			echo "<span class=H>".ucwords($word)."</span>";
    			}
    			else {
    				echo $word;
    			}
    			echo "&nbsp;";
    		}
    Is this too simple? Am I missing something?
    Your right I missed the word boundaries. The pattern can be simply replaced using: $sPattern = '/\b(' . implode('|', $aWords) . ')\b/i';. That will work otherwise as it echos instead of replaces. It will unfortunately replace a space with an &nbsp;, but that's easy enough to get around as well. Since it iterates each term, it will be slow.


    Quote Originally Posted by AndrewGSW View Post
    I did this in a slightly different way and don't know if the following code is of any interest - apologies if not.

    PHP Code:
    function onlyWholeWords(&$value$key) {
        
    // Ignores words after // comment delimiters.
        //$value = "/\b(" . $value . ")\b/";    // doesn't handle comments, so..
        //$value = "/^(?:(?!\/\/).)*\K\b(" . $value . ")\b/"; 
        // \K lookbehind alternative is not supported in PHP < 5.2.4, so use:
        
    $value "/^((?:(?!\/\/).)*)\b" $value "\b/";
    }
    function 
    addSpan(&$value$key$color='blue') {
        
    $value "$1<span style='color:$color'>" $value "</span>";
    }
    function 
    codeWords($code) {
        
    $keywords = array('as''break''case''class''continue''default'
            
    'do''elif''else''elseif''for''foreach''function''if'
            
    'new''null''return''self''switch''this''to''typeof'
            
    'until''var''void''while''with');
        
    $keywords2 $keywords;

        
    array_walk($keywords'onlyWholeWords');
        
    array_walk($keywords2'addSpan''blue');
        
    $code preg_replace($keywords$keywords2$code);
        return 
    $code;

    It might be of interest because it uses functions and it can be modified to use different colours for different (arrays of) words:

    PHP Code:
    function codeWords($code$colour)
    // ...
        
    array_walk($keywords2'addSpan'$colour); 
    That's neat, but it still won't work. The problem is that if you use str_replace it will become greedy on each iteration. If you use an array of pattern and replace then they will also be greedy since each evaluation is distinct on the subject. So it would ultimately give the same behaviour as an str_replace. If you change the span style to a span class, then add 'cat' (for concatination ), then you would end up with it replacing both the span to the cat with the class, as well as the class when it hits it further in. It would be useful for C syntax highlight, but not useful for a search highlight (albeit redundant since PHP has a builtin highlight function).
    Last edited by Fou-Lu; 12-08-2012 at 04:26 PM.

  • #8
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    @Fou-Lu Thank you. Actually, I recall now that I'm cheating

    PHP Code:
                        $line codeWords($line);       // blue keywords
                        
    $line str_replace('  ''&nbsp;'$line);
                        
    // Use @ to break-up keywords that shouldn't be colour-coded;
                        // use @@ to keep a single @ sign.
                        
    $line preg_replace('/((\@)(\@)?)/''$3'$line);
                        
    $html_lines .= "<li class=\"tab$count_fours\">$line</li>"
    I'm using at @ signs to break words that I wish to exclude. So my example is not directly relevant to the OPs question. Sorry for the confusion .
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • #9
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    PHP has a builtin highlight function
    Mmm, might investigate this, but then again.. I've already done it
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • #10
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,994
    Thanks
    4
    Thanked 2,662 Times in 2,631 Posts
    Quote Originally Posted by AndrewGSW View Post
    Mmm, might investigate this, but then again.. I've already done it
    You betcha:
    PHP Code:
    $sCode = <<<CODE
    <?php
    echo "This is some code";
    $aVar = array('var');
    printf('This is a variable: %s' PHP_EOL$aVar[0]); // And a comment
    ?>
    CODE;

    print highlight_string($sCode);
    There is also a highlight_file method. This will be faster than any user method that can be written of course.

  • #11
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    Mmm got that page open (highlight_string) but it's just for PHP code..

    My approach is for displaying database-content as code in a kindof-blog.
    Attached Thumbnails Attached Thumbnails Can someone see the error in my logic?-blogcode1.png  
    Last edited by AndrewGSW; 12-08-2012 at 05:14 PM.
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •