Merging preg_match_all and preg_replace - php

I have some code running which finds out hashtags in the string and turns them into links. I have done this using preg_match_all as shown below:
if(preg_match_all('/(#[A-z_]\w+)/', $postLong, $arrHashTags) > 0){
foreach ($arrHashTags[1] as $strHashTag) {
$long = str_replace($strHashTag, ''.$strHashTag.'', $postLong);
}
}
Also, for my search script, I need to bold the searched keywords in the result string. Something similar to the below code using preg_replace:
$string = "This is description for Search Demo";
$searchingFor = "/" . $searchQuery . "/i";
$replacePattern = "<b>$0<\/b>";
preg_replace($searchingFor, $replacePattern, $string);
The problem that I am having is that both have to work together and should be thrown as a combined result. One way I can think of is to run the resultant string from preg_match_all with the preg_replace code but what if the tags and the searched string are the same? The second block will bold my tag as well which is not desired.
update the code i'm running based on the answer given below but it still doesn't work
if(preg_match_all('/(#[A-z_]\w+)/', $postLong, $arrHashTags) > 0){
foreach ($arrHashTags[1] as $strHashTag) {
$postLong = str_replace($strHashTag, ''.$strHashTag.'', $postLong);
}
}
And immediately after this, i run this
$searchingFor = "/\b.?(?<!#)" . $keystring . "\b/i";
$replacePattern = "<b>$0<\/b>";
preg_replace($searchingFor, $replacePattern, $postLong);
Just so you know, this is all going inside a while loop, which is generating the list

You just need to modify you the search pattern to avoid ones that start with a '#'
$postLong = "This is description for Search Demo";
if(preg_match_all('/(#[A-z_]\w+)/', $postLong, $arrHashTags) > 0){
foreach ($arrHashTags[1] as $strHashTag) {
$postLong = str_replace($strHashTag, ''.$strHashTag.'', $postLong);
}
}
# This expression finds any text with 0 or 1 characters in front of it
# and then does a negative look-behind to make sure that the character isn't a #
searchingFor = "/\b.?(?<!#)" . $searchQuery . "\b/i";
$replacePattern = "<b>$0<\/b>";
preg_replace($searchingFor, $replacePattern, $postLong);
Or if you don't need an array of the available hashes for another reason, you could use preg_replace only.
$postLong = "This is description for #Search Demo";
$patterns = array('/(#[A-z_]\w+)/', "/\b.?(?<!#)" . $searchQuery . "\b/i");
$replacements = array(''.$0.'', ' "<b>$0<\/b>');
preg_replace($patterns, $replacements, $postLong);

Related

PHP extra whitespace not being deleted

I'm counting words in an article and removing common words such as "and" or "the".
I"m removing them by use of preg_replace
after it is done I do a quick clean of extra white space by using.
$search_body = preg_replace('/\s+/',' ',$search_body);
However I've got some very stubborn white space that will not go away. I've tried
if($word == "" OR $word == " "){
//chop it's head off
}
But the if statement does not see $word as being just whitespace. I've also tried printing it to the screen to get the raw data type of it and it's still just showing up blank.
Here is the full regex that I'm using.
$pattern = array(
'/\&quot\;/',
'/[0-9]/',
'/\,/',
'/\./',
'/\!/',
'/\#/',
'/\#/',
'/\$/',
'/\%/',
'/\^/',
'/\&/',
'/\*/',
'/\(/',
'/\)/',
'/\_/',
'/\"/',
'/\'/',
'/\:/',
'/\;/',
'/\?/',
'/\`/',
'/\~/',
'/\[/',
'/\]/',
'/\{/',
'/\}/',
'/\|/',
'/\+/',
'/\=/',
'/\-/',
'/–/',
'/°/',
'/\bthe\b/',
'/\band\b/',
'/\bthat\b/',
'/\bhave\b/',
'/\bfor\b/',
'/\bnot\b/',
'/\bwith\b/',
'/\byou\b/',
'/\bthis\b/',
'/\bbut\b/',
'/\bhis\b/',
'/\bfrom\b/',
'/\bthey\b/',
'/\bsay\b/',
'/\bher\b/',
'/\bshe\b/',
'/\bwill\b/',
'/\bone\b/',
'/\ball\b/',
'/\bwould\b/',
'/\bthere\b/',
'/\btheir\b/',
'/\bwhat\b/',
'/\bout\b/',
'/\babout\b/',
'/\bwho\b/',
'/\bget\b/',
'/\bwhich\b/',
'/\bwhen\b/',
'/\bmake\b/',
'/\bcan\b/',
'/\blike\b/',
'/\btime\b/',
'/\bjust\b/',
'/\bhim\b/',
'/\bknow\b/',
'/\btake\b/',
'/\bpeople\b/',
'/\binto\b/',
'/\byear\b/',
'/\byour\b/',
'/\bgood\b/',
'/\bsome\b/',
'/\bcould\b/',
'/\bthem\b/',
'/\bsee\b/',
'/\bother\b/',
'/\bthan\b/',
'/\bthen\b/',
'/\bnow\b/',
'/\blook\b/',
'/\bonly\b/',
'/\bcome\b/',
'/\bits\b/', //it's?
'/\bover\b/',
'/\bthink\b/',
'/\balso\b/',
'/\bback\b/',
'/\bafter\b/',
'/\buse\b/',
'/\btwo\b/',
'/\bhow\b/',
'/\bour\b/',
'/\bwork\b/',
'/\bfirst\b/',
'/\bwell\b/',
'/\bway\b/',
'/\beven\b/',
'/\bnew\b/',
'/\bwant\b/',
'/\bbecause\b/',
'/\bany\b/',
'/\bthese\b/',
'/\bgive\b/',
'/\bday\b/',
'/\bmost\b/',
'/\bare\b/',
'/\bwas\b/',
'/\<\w+\>/', '/\<\/\w+\>/',
'/\b\w{1}\b/', //1 letter word
'/\b\w{2}\b/', //2 letter word
'/\//',
'/\</',
'/\>/'
);
$search_body = strip_tags($body);
$search_body = strtolower($search_body);
$search_body = preg_replace($pattern, ' ', $search_body);
$search_body = preg_replace('/\s+/',' ',$search_body);
$search_body = explode(" ", $search_body);
When exploded blank values show up left and right
Example text that I am using is too long to post here. But I copied and pasted
This article to give it a test and it showed 32 counts of white space, not including the white space in front of or behind of other words even after using trim().
Here's a js.fiddle of the raw data that is being handled by php.
htmlentities and htmlspecialchars also show nothing.
Here's the code counts all the values and puts them into one.
$inhere = array();
$body_hold = array();
foreach($search_body as $value){
$value = trim($value);
if(in_array($value, $inhere) && $value != ""){
$key = array_search($value, $inhere);
$body_hold[$key]['count'] = $body_hold[$key]['count']+1;
}elseif($value != ""){
$inhere[] = $value;
$body_hold[] = array(
'count' => 1,
'word' => $value
);
}
}
rsort($body_hold);
Basic foreach to see values.
foreach($body_hold as $value){
$count = $value['count'];
$word = trim($value['word']);
echo "Count: ".$count;
echo " Word: ".$word;
echo '<br>';
}
Here's a PHP example of what it's returning
Are you sure you put the exact same data you're processing in the js.fiddle? Or did you get it from a subsequent post-processed step?
It's obviously a Wikipedia article. I went to that article on Wikipedia and opened it in Edit mode, and saw that there are s in the raw wikitext. However, those nbsp's don't appear in your js.fiddle data.
TL;DR: Check for in your processing (and convert to spaces, etc.).
This character 160 looks like space but it's not, replacing all of them to the regular spaces (32) and then removing all the double spaces will fix your problem.
$search_body = str_replace(chr(160), chr(32), $search_body);
$search_body = trim(preg_replace('/\s+/', ' ', $search_body));

Highlighting extracted keywords inside extracted description

Okay suppose we would like to get title,keywords and description of website so i'm going to use the following function
<?PHP
function getInfo($URL)
{
$getInfo= get_meta_tags($URL);
return $getInfo;
}
$URL = "http://www.my_site.com"; // URL
// Applying the function
$_getInfo = getInfo($URL);
// Print the results.
echo $_getInfo ["keywords"]."<br>"; // gives keywords
echo $_getInfo ["description"]."<br>"; // gives description
?>
Yet,everything if fine but suppose the results as following
Keywords
php,profitable,share
Description
Advanced profitable and featured script to share
As in this example we've some keywords found in description profitable and share
The question is how to highlight keywords that only found in description!!
I will add the following css
<style>
.highlight{background: #CEDAEB;}
.highlight_important{background: #F8DCB8;}
</style>
and will add this function to alter between two different colors just like in css code
<?PHP
function hightlight($str, $keywords = '')
{
$keywords = preg_replace('/\s\s+/', ' ', strip_tags(trim($keywords))); // filter
$style = 'highlight';
$style_i = 'highlight_important';
$var = '';
foreach (explode(' ', $keywords) as $keyword) {
$replacement = "<span class='".$style."'>".$keyword."</span>";
$var .= $replacement." ";
$str = str_ireplace($keyword, $replacement, $str);
}
$str = str_ireplace(rtrim($var), "<span class='".$style_i."'>".$keywords."</span>", $str);
return $str;
}
?>
Now applying both (Not working)
$string = hightlight($_getInfo["description"], $_getInfo ["keywords"]);
echo $string;
Why not working cause it define $_getInfo ["keywords"] as one word php,profitable,share
which indeed not found in description in that shape.
so how can i apply it by using explode or foreach (i guess) so the out put be like this :
I wonder if there was another way to do it if mine looks not good way. ~ Thanks
Since your keywords are in list format you need to:
foreach(explode(',', $keywords) as $keyword)

PHP using prefix tags to linkify text

I'm trying to write a code library for my own personal use and I'm trying to come up with a solution to linkify URLs and mail links. I was originally going to go with a regex statement to transform URLs and mail addresses to links but was worried about covering all the bases. So my current thinking is perhaps use some kind of tag system like this:
l:www.google.com becomes http://www.google.com and where m:john.doe#domain.com becomes john.doe#domain.com.
What do you think of this solution and can you assist with the expression? (REGEX is not my strong point). Any help would be appreciated.
Maybe some regex like this :
$content = "l:www.google.com some text m:john.doe#domain.com some text";
$pattern = '/([a-z])\:([^\s]+)/'; // One caracter followed by ':' and everything who goes next to the ':' which is not a space or tab
if (preg_match_all($pattern, $content, $results))
{
foreach ($results[0] as $key => $result)
{
// $result is the whole matched expression like 'l:www.google.com'
$letter = $results[1][$key];
$content = $results[2][$key];
echo $letter . ' ' . $content . '<br/>';
// You can put str_replace here
}
}

Replace text ignoring HTML tags

I have a simple text with HTML tags, for example:
Once <u>the</u> activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, <i>only</i> while the activity is in the resumed state can the <b>lifecycle</b> of a <hr/> fragment change independently.
I need to replace some parts of this text ignoring its html tags when I do this replace, for example this string - Thus, <i>only</i> while I need to replace with my string Hello, <i>its only</i> while . Text and strings to be replaced are dynamically. I need your help with my preg_replace pattern
$text = '<b>Some html</b> tags with <u>and</u> there are a lot of tags <i>in</i> this text';
$arrayKeys= array('Some html' => 'My html', 'and there' => 'is there', 'in this text' => 'in this code');
foreach ($arrayKeys as $key => $value)
$text = preg_replace('...$key...', '...$value...', $text);
echo $text; // output should be: <b>My html</b> tags with <u>is</u> there are a lot of tags <i>in</i> this code';
Please help me to find solution. Thank you
Basically we're going to build dynamic arrays of matches and patterns off of plain text using Regex. This code only matches what was originally asked for, but you should be able to get an idea of how to edit the code from the way I've spelled it all out. We're catching either an open or a close tag and white space as a passthru variable and replacing the text around it. This is setup based on two and three word combinations.
<?php
$text = '<b>Some html</b> tags with <u>and</u> there are a lot of tags <i>in</i> this text';
$arrayKeys= array(
'Some html' => 'My html',
'and there' => 'is there',
'in this text' =>'in this code');
function make_pattern($string){
$patterns = array(
'!(\w+)!i',
'#^#',
'! !',
'#$#');
$replacements = array(
"($1)",
'!',
//This next line is where we capture the possible tag or
//whitespace so we can ignore it and pass it through.
'(\s?<?/?[^>]*>?\s?)',
'!i');
$new_string = preg_replace($patterns,$replacements,$string);
return $new_string;
}
function make_replacement($replacement){
$patterns = array(
'!^(\w+)(\s+)(\w+)(\s+)(\w+)$!',
'!^(\w+)(\s+)(\w+)$!');
$replacements = array(
'$1\$2$3\$4$5',
'$1\$2$3');
$new_replacement = preg_replace($patterns,$replacements,$replacement);
return $new_replacement;
}
foreach ($arrayKeys as $key => $value){
$new_Patterns[] = make_pattern($key);
$new_Replacements[] = make_replacement($value);
}
//For debugging
//print_r($new_Patterns);
//print_r($new_Replacements);
$new_text = preg_replace($new_Patterns,$new_Replacements,$text);
echo $new_text."\n";
echo $text;
?>
Output
<b>My html</b> tags with <u>is</u> there are a lot of tags <i>in</i> this code
<b>Some html</b> tags with <u>and</u> there are a lot of tags <i>in</i> this text
Here we go. this piece of code should work, assuming you're respecting only twp constraints :
Pattern and replacement must have the same number of words. (Logical, since you want to keep position)
You must not split a word around a tag. (<b>Hel</b>lo World won't work.)
But if these are respected, this should work just fine !
<?php
// Splits a string in parts delimited with the sequence.
// '<b>Hey</b> you' becomes '~-=<b>~-=Hey~-=</b>~-= you' that make us get
// array ("<b>", "Hey" " you")
function getTextArray ($text, $special) {
$text = preg_replace ('#(<.*>)#isU', $special . '$1' . $special, $text); // Adding spaces to make explode work fine.
return preg_split ('#' . $special . '#', $text, -1, PREG_SPLIT_NO_EMPTY);
}
$text = "
<html>
<div>
<p>
<b>Hey</b> you ! No, you don't have <em>to</em> go!
</p>
</div>
</html>";
$replacement = array (
"Hey you" => "Bye me",
"have to" => "need to",
"to go" => "to run");
// This is a special sequence that you must be sure to find nowhere in your code. It is used to split sequences, and will disappear.
$special = '~-=';
$text_array = getTextArray ($text, $special);
// $restore is the array that will finally contain the result.
// Now we're only storing the tags.
// We'll be story the text later.
//
// $clean_text is the text without the tags, but with the special sequence instead.
$restore = array ();
for ($i = 0; $i < sizeof ($text_array); $i++) {
$str = $text_array[$i];
if (preg_match('#<.+>#', $str)) {
$restore[$i] = $str;
$clean_text .= $special;
}
else {
$clean_text .= $str;
}
}
// Here comes the tricky part.
// We wanna keep the position of each part of the text so the tags don't
// move after.
// So we're making the regex look like (~-=)*Hey(~-=)* you(~-=)*
// And the replacement look like $1Bye$2 me $3.
// So that we keep the separators at the right place.
foreach ($replacement as $regex => $newstr) {
$regex_array = explode (' ', $regex);
$regex = '(' . $special . '*)' . implode ('(' . $special . '*) ', $regex_array) . '(' . $special . '*)';
$newstr_array = explode (' ', $newstr);
$newstr = "$1";
for ($i = 0; $i < count ($regex_array) - 1; $i++) {
$newstr .= $newstr_array[$i] . '$' . ($i + 2) . ' ';
}
$newstr .= $newstr_array[count($regex_array) - 1] . '$' . (count ($regex_array) + 1);
$clean_text = preg_replace ('#' . $regex . '#isU', $newstr, $clean_text);
}
// Here we re-split one last time.
$clean_text_array = preg_split ('#' . $special . '#', $clean_text, -1, PREG_SPLIT_NO_EMPTY);
// And we merge with $restore.
for ($i = 0, $j = 0; $i < count ($text_array); $i++) {
if (!isset($restore[$i])) {
$restore[$i] = $clean_text_array[$j];
$j++;
}
}
// Now we reorder everything, and make it go back to a string.
ksort ($restore);
$result = implode ($restore);
echo $result;
?>
Will output Bye me ! No, you don't need to run!
[EDIT] Now supporting a custom pattern, which allows to avoid adding useless spaces.

PHP Coding Restrict Preg_replace function from multiple tags

I have a great little script that will search a file and replace a list of words with their matching replacement word. I have also found a way to prevent preg_replace from replacing those words if they appear in anchor tags, img tags, or really any one tag I specify. I would like to create an OR statement to be able to specify multiple tags. To be clear, I would like to prevent preg_replace from replacing words that not only appear in an anchor tag, but any that appear in an anchor,link,embed,object,img, or span tag. I tried using the '|' OR operator at various places in the code with no success.
<?php
$data = 'somefile.html';
$data = file_get_contents($data);
$search = array ("/(?!(?:[^<]+>|[^>]+<\/a>))\b(red)\b/is","/(?!(?:[^<]+>|[^>]+<\/a>))\b(white)\b/is","/(?!(?:[^<]+>|[^>]+<\/a>))\b(blue)\b/is");
$replace = array ('Apple','Potato','Boysenberry');
echo preg_replace($search, $replace, $data);?>
print $data;
?>
looking at the first search term which basically says to search for "red" but not inside :
"/(?!(?:[^<]+>|[^>]+<\/a>))\b(red)\b/is"
I am trying to figure out how I can somehow add <\/link>,<\/embed>,<\/object>,<\/img> to this search so that preg_replace doesn't replace 'red' in any of those tags either.
Something like this?:
<?php
$file = 'somefile.html';
$data = file_get_contents($file);
print "Before:\n$data\n";
$from_to = array("red"=>"Apple",
"white"=>"Potato",
"blue"=>"Boysenberry");
$tags_to_avoid = array("a", "span", "object", "img", "embed");
$patterns = array();
$replacements = array();
foreach ($from_to as $from=>$to) {
$patterns[] = "/(?!(?:[^<]*>|[^>]+<\/(".implode("|",$tags_to_avoid).")>))\b".preg_quote($f
rom)."\b/is";
$replacements[] = $to;
}
$data = preg_replace($patterns, $replacements, $data);
print "After:\n$data\n";
?>
Result:
Before:
red
<span class="blue">red</span>
blue<div class="blue">white</div>
<div class="blue">red</div>
After:
red
<span class="blue">red</span>
Boysenberry<div class="blue">Potato</div>
<div class="blue">Apple</div>

Categories