Page 1 of 1

linking text

Posted: Thu May 29, 2003 7:57 am
by nerd
HowdA All....

Having a big prob I am hoping someone can help with.

Essentially, I am trying to create a function that will scan text and link text that has been predefined.

I have an array (pulled from a DB) of words and IDs eg. 115, Bob

If my text looks like this:

Code: Select all

My name is Bob. bob is neat. bobby isnt. Bobs is. So is Bobs.
with:

Code: Select all

My name is <a href="115">Bob</a>. <a href="115">bob</a> is neat. bobby isnt. <a href="115">Bobs</a> is. So is <a href="115">Bobs</a>.
I don't want to use the text from the array if I can help it so I dont have to worry about screwing up the case. (i.e. I dont want to replace bOb with Bob as that would change the integrity of the message)
I want to be able to say its a match if: 1- there is a space after the match, 2- there is a comma, period or other thingee, 3- is the word is plural (i.e. ends with an s followed by a space).

Do I need medication? yes. Am I trying to do something I can't? Don't know... so far I havent been able to get this to come together. I have gotten it 99% of the way there, but I dont think its very efficient and the code ends up only linking bob in the term bobs.

Anyway... any help is very much appreciated.

Thanks all

Posted: Thu May 29, 2003 8:33 am
by mikusan
I am sorry but i can't quite understand what you want to do, or why you want to do it the way you are... :oops:

not surprised!

Posted: Thu May 29, 2003 9:47 am
by nerd
Its a little hard for me to explain.

I have a site where I want to be able to automatically highlight and link certain words.

Lets say On one page I have the following message:
Here is an article on a technical widget that I am talking about.
I want to be able to replace all instances of widget with:

Code: Select all

<a href="definitions.php?id=151">widget</a>
but with these restrictions:

I want to use the original text between the anchors to save the integrity of the text so if they type wIdget, it still looks like wIdget is linked.

I want to be able to include the following:
widgets
widget.
Widget,
but I dont want
widgetings.

Hope Im not asking for the impossible :)

TIA

Here is the current code

Posted: Thu May 29, 2003 10:27 am
by nerd
Thought maybe this would help calrify.

This is the code that has me about 90% of the way there:
I know there are several inefficientcies... any help there would be most grateful. Although im not new to programming, I am brand new to PHP.

Hope this clarifies:

Code: Select all

<?php


function prepare_message_defs($message)
{


        //Defaults
        $newcontent = "";

        //Constant URL tag to the left of word
        $left_side="<a href="http://www.samuelsweet.com/board/viewtopic.php?p={URL}&up=1" target="_defs" onclick="window.open('http://www.samuelsweet.com/board/viewtopic.php?p={URL}&up=1', 'definitions', 'height=200, width=500, resize=yes, scrollbars= yes'); return false;" class="postlink">";
        //constant URL end tag for the right of word
		$right_side ="</a>";

        //fake the look up for now-- normally pulled from datasource
        $defs=array('id'=>array(5580,5580,5585),'desc' =>array('greenie','bacterial infection','mould'));
        $n=count($defs) +1;

        //pad out message
		$message = ' ' .$message . ' ';

        //loop through defs
        for ($i=0; $i<$n; $i++) {
                   $position=0;

                   do {
                        //get position of first match
                        $position=strpos(strtolower($message),strtolower($defs['desc'][$i]),$position);

                        //is there a match?
                        if ($position>0){
                            //swap the {URL} and {Description} placeholders for current rowset
							$new_left=str_replace(array("{URL}","{DESCRIPTION}"),array($defs['id'][$i],$defs['desc'][$i]),$left_side);

                            //Get offset of the length of the description+id+url tag
							$description_len=strlen($defs['desc'][$i]);
							$id_len=strlen($defs['id'][$i]);
							$link_len=strlen($new_left);

							$eend=strpos($message,' ',$position);
							if ($eend>0){
								$eend=$description_len;
							}

                            //Break message up into front, middle, and last
							$firstpart=substr($message,0,$position);
							$middlepart=substr($message,$position, $eend);
							$lastpart=substr($message,($position + $eend));

                            //check to get the next character
							$check=strtolower(substr($lastpart,0,1));

                            
                            //If next letter is an s... go to the NEXT letter
                            if ( $check=='s' ){
                            	$check=strtolower(substr($lastpart,1,1));
                            }
                                                    
							switch ( $check ) {
						    	case ' ':
							        $check=true;
							        break;
							    case '!':
							        $check=true;
							        break;
							    case '?':
							        $check=true;
							        break;
							    case '.':
							        $check=true;
							        break;
						    	case ',':
        							$check=true;
	        						break;
								default:
									$check=false;
							}

                            //Slap it together and add the diff to $position
							if ($check===true){
								$message=$firstpart . $new_left . $middlepart . '</a>' . $lastpart;
								$position=$position + $link_len + 4;
							}else{
								$position=$position + $description_len +1;
							}

                        }

                   } while ($position!==false);
        		}

        		$message=trim($message);


        return $message;


}

$message="hi ma. Im greenie to get some mould from moUlds some bacterial infections.";

echo('<br />This is the message before processing:<br />' . $message);
$message=prepare_message_defs($message);
echo('<br />Here it is after:<br />' . $message);
echo('<br />What it needs to be is:<br />');
echo('hi ma. Im <a href="http://www.samuelsweet.com/board/viewtopic.php?p=5580&up=1" target="_defs"
	  onclick="window.open(''http://www.samuelsweet.com/board/viewtopic.php?p=5580&up=1'', ''definitions'', ''height=200, width=500, resize=yes, scrollbars= yes''); return false;" 
	  class="postlink">greenie</a> to get some <a href="http://www.samuelsweet.com/board/viewtopic.php?p=5585&up=1" target="_defs"
	  onclick="window.open(''http://www.samuelsweet.com/board/viewtopic.php?p=5585&up=1'', ''definitions'', ''height=200, width=500, resize=yes, scrollbars= yes''); return false;"
	  class="postlink">mould</a> from <a href="http://www.samuelsweet.com/board/viewtopic.php?p=5585&up=1" target="_defs"
	  onclick="window.open(''http://www.samuelsweet.com/board/viewtopic.php?p=5585&up=1'', ''definitions'', ''height=200, width=500, resize=yes, scrollbars= yes''); return false;"
	  class="postlink">moUlds</a> some <a href="http://www.samuelsweet.com/board/viewtopic.php?p=5580&up=1" target="_defs"
	  onclick="window.open(''http://www.samuelsweet.com/board/viewtopic.php?p=5580&up=1'', ''definitions'', ''height=200, width=500, resize=yes, scrollbars= yes''); return false;"
	  class="postlink">bacterial infections</a>.');

?>

Posted: Thu May 29, 2003 1:19 pm
by jason
I would like to introduce you to regular expressions. All that code you are doing can be replaced with on line:

Code: Select all

<?php

$text = 'Here is an article on a technical widget that I am talking about.
Here is an article on a technical widgets that I am talking about.
Here is an article on a technical widget. that I am talking about.
Here is an article on a technical widgets. that I am talking about.
Here is an article on a technical widget, that I am talking about.
Here is an article on a technical widgets, that I am talking about.
Here is an article on a technical WidGet that I am talking about.
Here is an article on a technical widgEts that I am talking about.
Here is an article on a technical widgetings that I am talking about.';

preg_match_all('|\b(widgets?)\b|i', $text, $results);

print_r($results);

$result = preg_replace('|\b(widgets?)\b|i', '<a href="link">\\1</a>', $text);

print_r($result);

?>
The specific line is the preg_replace() function. The first argument searches is the regex.

Code: Select all

|\b(widgets?)\b|i
Basically, that says to find any word (\b) widget with an optional 's' on the end. The i makes it case insensitive.

The second argument is what to replace.

Code: Select all

&lt;a href="link"&gt;\\1&lt;/a&gt;
Specifically, it takes whatever it finds in the () and puts it there.

What you could do is something like this:

Code: Select all

<?php

$result = preg_replace('|\b('.$word.'?)\b|i', '<a href="'.$url.'">\\1</a>', $text);

?>
And simple set $word/$url with the appropriate values.

Find out more here: http://ca.php.net/manual/en/ref.pcre.php

Wooohooo

Posted: Thu May 29, 2003 2:03 pm
by nerd
Spot on... Thanks for that...

I have been looking into preg_replace and regular expressions but so far have found very little good entry level instruction into them.

Thanks for taking the time to help me through that. Here is my final function though I cant help but feel the way I am doing it still leaves a bit to be desired... would you have time to give me a yay or nay on how I fill the values in or does it look okish?

Code: Select all

function Def_All($message){


    $defs=array('id'=>array(5580,5580,5585),'desc' =>array('greenie','bacterial infection','mould'));
    $n=count($defs) +1;
    //Constant URL tag to the left of word
        $left_side="<a href="viewtopic.php?p={URL}&up=1" target="_defs" onclick="window.open('viewtopic.php?p={URL}&up=1', 'definitions', 'height=200, width=500, resize=yes, scrollbars= yes'); return false;" class="postlink">";
    for ($i=0; $i<$n; $i++) {

		$new_left=str_replace(array("{URL}","{DESCRIPTION}"),array($defs['id'][$i],$defs['desc'][$i]),$left_side);
		$message = preg_replace('|\b(' . $defs['desc'][$i] . 's?)\b|i',  $new_left .'\\1</a>', $message);

	}

	return $message;

}
Thanks again... I have spent the last 2 afternoons on this!

One more thing...

Posted: Thu May 29, 2003 2:16 pm
by nerd
Dont mean to ask for an inch and take a mile... but...

Is there anyway to prevent the swap from being made if it is in middle of a link?

TIA

Posted: Thu May 29, 2003 2:44 pm
by jason
This is how I would do it:

Code: Select all

<?php

$message = 'hi ma. Im greenie to get some mould from moUlds some bacterial infections.';

echo Def_All($message);

function Def_All ( $message )
{
	// What you called the $id's
	$links = array(5580,5580,5585);
	// and the $desc's
	$desc = array('greenie','bacterial infection','mould');
	
	// Create the links
	array_walk($links, 'array_walk_makeLink');
	// Turn the words in $desc into regex's
	array_walk($desc, 'array_walk_makeRegex');
	
	// A single preg_replace call that does everything for us
	$message = preg_replace($desc,  $links, $message);
	
	return  $message;
}

function array_walk_makeRegex ( &$val )
{
	$val = '|\b(' . $val . 's?)\b|i';
}

function array_walk_makeLink ( &$val )
{
	$left_side='<a href="viewtopic.php?p=%s&up=1" target="_defs" onclick="window.open(''viewtopic.php?p=%s&up=1'', ''definitions'', ''height=200, width=500, resize=yes, scrollbars= yes''); return false;" class="postlink">\\1</a>';
	$val = sprintf($left_side, $val, $val);
}

?>
Of course, that's up to you to determine where the $links and $desc's come from, or how they are defined. However, this is how I would do it.

Works a treat

Posted: Thu May 29, 2003 4:07 pm
by nerd
That makes sense and works a treat...

Still boggled about how to prevent it from replacing words in anchors already though... Been trying to get my head around the regex for it but am not comming up with much. Any ideas?

TIA