Replace words in a a string randomly - php

I'm trying to write a script that will take a text string and will allow me replace random words. For example:
$str = "The quick brown fox jumps over the lazy dog";
I will out put as and replace couple words like this:
The quick ______ fox jumps over the ____ dog
I can probably do this by first splitting the string into array
$arr = str_word_count($str, 1);
And then replace $arr[2] and $arr[7].
The issue that I think I'll have if there are non-words in the string, like punctuation:
$str = "The quick brown fox, named Jack, jumps over the lazy dog; and Bingo was his...";
How do I go about resolving this? Ideas?

You can do it like this:
$test1 = "test1";
$test2 = "test2";
$test3 = "Bingo2";
// set new words
$str = "The quick brown fox, named Jack, jumps over the lazy dog; and Bingo was his...";
$re = explode(" ", $str);
// split them on space in array $re
echo $str . "<br>";
$num = 0;
foreach ($re as $key => $value) {
echo $value . "<br>";
$word = "";
switch (true) {
case (strpos($value, 'Jack') !== false):
// cheak if each value in array has in it wanted word to replace
// and if it does
$new = explode("Jack", $value);
// split at that word just to save punctuation
$word = $test1 . $new[1];
//replace the word and add back punctuation
break;
case (strpos($value, 'dog') !== false):
$new1 = explode("dog", $value);
$word = $test2 . $new1[1];
break;
case (strpos($value, 'Bingo') !== false):
$new2 = explode("Bingo", $value);
$word = $test3 . $new2[1];
break;
default:
$word = $value;
// if no word are found to replace just leave it
}
$re[$num++] = $word;
//push new words in order back into array
};
echo implode(" ", $re);
// join back with space
Result:
The quick brown fox, named test1, jumps over the lazy test2; and Bingo2 was his...
It works with or without punctuation.
But keep in mind if you have Jack and Jacky for example you will need to add additional logic such as checking if punctuation part does not have any letters in it with Regex to match only letters, if it does skip it, it means it was not full match. Or soothing similar.
EDIT (based on comments):
$wordstoraplce = ["Jacky","Jack", "dog", "Bingo","dontreplace"];
$replacewith = "_";
$word = "";
$str = "The quick brown fox, named Jack, jumps over the lazy dog; and Bingo was his...";
echo $str . "<br>";
foreach ($wordstoraplce as $key1 => $value1) {
$re = explode(" ", $str);
foreach ($re as $key => $value) {
if((strpos($value, $value1) !== false)){
$countn=strlen($value1);
$new = explode($value1, $value);
if (!ctype_alpha ($new[1])){
$word = " " . str_repeat($replacewith,$countn) . $new[1]. " ";
}else{
$word = $value;
}
}else{
$word = $value;
};
//echo $word;
$re[$key] = $word;
};
$str = implode(" ", $re);
};
echo $str;
RESULT:
The quick brown fox, named Jack, jumps over the lazy dog; and Bingo was his...
The quick brown fox, named ____, jumps over the lazy ___; and _____ was his...

I think a much better apporach would be to use a regex, because you don't just allow commas, but everything which is not a word character. Also regexes are much faster than normal splittings or substrings in loops.
My Solution would be:
<?php
function randomlyRemovedWords($str)
{
$sentenceParts = [];
$wordCount = preg_match_all("/([\w']+)([^\w']*)/", $str, $sentenceParts, PREG_SET_ORDER);
for ($i = 0;$i < $wordCount / 4;$i++)
{ //nearly every fourth word will be changed
$index = rand(0, $wordCount - 1);
$sentenceParts[$index][1] = preg_replace("/./", "_", $sentenceParts[$index][1]);
}
$str = "";
foreach ($sentenceParts as $part)
{
$str .= $part[1] . $part[2];
}
return $str;
}
echo randomlyRemovedWords("The quick brown fox, doesn't jumps over, the lazy dog.");
echo "\n<br>\n";
echo randomlyRemovedWords("The quick brown fox, jumps over, the lazy dog.");
which results in
The quick brown ___, _______ jumps over, the ____ dog.
<br>
The quick brown fox, jumps ____, ___ ____ dog.
This way you can be sure to ignore all nonword characters and remove words randomly.

Related

Check if a word occur in string and not to be in first and last

I am trying to check if word is occur in a string but not to be the first and last word, if its true then remove the space after and before of the word and replace with a underscore.
Input:
$str = 'This is a cool area";
Output:
$str = 'This is a_cool_area";
I want to check that the word 'cool' is inside the string but not a first and last word. if yes the remove the space & replace with '_'
You can use preg_replace to do this job, using this regex:
/(?<=\w)\s+(' . $word . ')\s+(?=\w)/i
which looks for the word, surrounded by at least one word character on either side (to prevent matching at the beginning or ending of the sentence). Usage in PHP:
$str = 'This is a cool area';
$word = 'cool';
$str = preg_replace('/(?<=\w)\s+(' . $word . ')\s+(?=\w)/i', '_$1_', $str);
echo $str . "\n";
$str = ' Cool areas are cool ';
$str = preg_replace('/(?<=\w)\s+(' . $word . ')\s+(?=\w)/i', '_$1_', $str);
echo $str . "\n";
Output:
This is a_cool_area
Cool areas are cool
Demo on 3v4l.org
function checkWord($str, $word)
{
$arr = explode(" ", $str);
$newArr = array_slice($arr, 1, -1);
$key = array_search($word, $newArr);
if($key !== false)
{
return implode('_',array_slice($arr, $key, 3));
}
else
{
return $str;
}
}
echo checkWord('This is a cool area', 'cool');

How to insert character inside a word while keeping the case

I want to insert a character inside a word in a string if a word match is found while keeping the case. This code works fine but I have to specify the resulting word.
$string = "Quick brown fOx jumps right over the lazy dog.";
$swears = array(
"BROWN" => "BRO.WN",
"fox" => "f.ox",
"Dog" => "D.og",
);
$filtered = str_ireplace(array_keys($swears), array_values($swears), $string);
The problem with this code is any "brown" becomes BRO.WN
Is it possible to insert a character if the word matches. Like Brown becomes Bro.wn; brown becomes bro.wn while keeping the case.
There are probably much better ways to do that, but here is the only answer I came up with :
foreach($swears as $swear => $modified_swear) {
$swear_pos = stripos($string, $swear);
if($swear_pos !== false) {
$swear_len = strlen($swear);
if($swear_len >= 3) {
$new_string = substr($string, 0, $swear_pos);
$new_string .= substr($string, $swear_pos, $swear_len-2);
$new_string .= '.';
$new_string .= substr($string, $swear_pos+($swear_len-2));
$string = $new_string;
}
}
}
This code works only if you actually was trying to add a single dot before the two last characters of a swear.
EDIT :
New code that can modify all occurences of a list of words.
$searched_pattern = '/\b(?:';
foreach($swears as $swear => $modified_swear) {
$searched_pattern .= '('.$swear.')|';
}
$searched_pattern = rtrim($searched_pattern, '|');
$searched_pattern .= ')\b/i';
$string = preg_replace_callback(
$searched_pattern,
function($matches) {
$word = $matches[0];
$swear_len = strlen($word);
if($swear_len >= 3) {
$new_word .= substr($word, 0, $swear_len-2);
$new_word .= '.';
$new_word .= substr($word, $swear_len-2);
$word = $new_word;
}
return $word;
},
$string
);
I'm not exactly clear what you want?
There are alternatives for this test. Then do a str_replace inserting a char into a specific position.
<?php
$string = "Quick brown fOx jumps right over the lazy dog.";
$swears = array(
"BROWN" => "BRO.WN",
"fox" => "f.ox",
"Dog" => "D.og"
);
$string_arr = explode(" ",$string);
$swears_arr = array_keys($swears);
foreach ($swears as $swear_key => $swear_word) {
foreach ($string_arr as $key => $word) {
if (preg_replace('/[^a-z]+/i', '', strtolower($word)) == strtolower($swear_key)) {
$string_arr[$key] = substr_replace($word, '.', 1, 0);
}
}
}
// put the sentence back together:
$new_string = implode(" ",$string_arr);
print_r($new_string);
?>

Check if multiple words exist in a sentence

I have the following :
Sentence :
"This is a red apple"
pattern to check :
red & apple.
Both sentence and pattern to check are user generated.
$sentence = "This is a red apple";
$words = array('red','apple');
$ch = implode("|",$words);
$pattern = '/[$ch]/';
if(preg_match($pattern, $sentence))
{
// Do something if the sentence contains red & apple
}
When i execute that code, i get nothing (nothing is displayed). When i do echo on $pattern it returns it as a whole string instead.
How can i fix this ? What am i missing ?
change $pattern = '/[$ch]/';
to
$pattern = '/('.$ch.')/'; or $pattern = '/['.$ch.']';
<?php
$sentence = "This is a red apple";
$words = array('apple','red');
$ch = implode("|",$words);
echo $pattern = '/('.$ch.')/';
if(preg_match($pattern, $sentence))
{
echo ' Do something if the sentence contains red & apple';
}else
{
echo 'nothing happpen';
}
?>
check if both word match
<?php
$sentence = "This is a red apple";
$words = array('red','apple');
$ch = implode("|",$words);
echo $pattern = '['.$ch.']';
if(preg_match_all($pattern, $sentence,$matches) == 2)
{
echo ' Do something if the sentence contains red & apple';
}else
{
echo 'nothing happpen';
}
?>
You also check how many word matched using
echo count($matches[0]);
$matches is array contain word are matched
You need to take care about quotes while using variables within quotes you need to update
$pattern = '/[$ch]/';
into
$pattern = "/($ch)/";
^^ ^^ ^^ ^^
You need to update your regex pattern also, so your code looks like as
$sentence = "This is a red apple";
$words = array('red','apple');
$ch = implode("|",$words);
$pattern = "/($ch)/";
if(preg_match_all($pattern, $sentence,$m))
{
echo "yes \n";
print_r($m);
}
Instead of regex I'll use array_intersect along with str_word_count like as
$sentence = "This is a red apple";
$words = array('red','apple','blue');
$var = count(array_intersect(str_word_count($sentence,1),$words));
if(count($words == $var)){
echo "Yes got it";
}
Demo
Demo2

How to get only characters highlighted from a string in php?

I have a string and some words, i want to highlight those words which match with string, and also i want to print only those words which are highlighted, like if apple matches, then only apple must be printed.
$string = "apple computer";
$keyword = "apple,orange,bike";
I am using the following function to highlight specific characters in a string.
$str = preg_replace("/($keyword)/i","<span style='color:orange;'>$0</span>",$string);
The problem is I want to show only those characters which are highlighted, currently it shows all the characters.
This would meet your need.
$string = " apple computer orange";
$keywords = "apple, orange";
$exp_kwd = explode(",", $keywords);
$res = "<span style='color:orange;'>";
foreach($exp_kwd as $val){
if(strpos($string, trim($val))){
$res .= $val." ";
}
}
$res = $res."</span>";
echo $res;
Hopefully this also will work
$string = "apple computer orange tested";
$keyword = "apple,orange,bike,tested";
$pattern="/".str_replace(",","/,/",$keyword)."/";
$pattern=explode(",",$pattern);
$string=explode(" ",$string);
$keyword =explode(",",$keyword);
$string=implode(",",(preg_filter($pattern, $keyword, $string)));
echo $string="<span style='color:orange;'>$string</span>";
$string = "Im On #Here";
$keyword = "#";
$var = strrchr($string,$keyword);
if(empty($var))
{
echo 'No Occerunce Found';
}
else
{
echo '<span style="color:orange;">'.$var.'</span>';
}
phpfiddle Preview

Using PHP to find key words in text file arsort()

I am trying to use a script to search a text file and return words that meet certain criteria:
*The word is only listed once
*They are not one words in an ignore list
*they are the top 10% of the longest words
*they are not repeating letters
*The final list would be a random ten that met the above criteria.
*If any of the above were false then words reported would be null.
I've put together the following but the script dies at arsort() saying it expects an array. Can anyone suggest a change to make arsort work? Or suggest an alternative (simpler) script to find metadata?**I realize this second question may be a question better suited for another StackExchange.
<?php
$fn="../story_link";
$str=readfile($fn);
function top_words($str, $limit=10, $ignore=""){
if(!$ignore) $ignore = "the of to and a in for is The that on said with be was by";
$ignore_arr = explode(" ", $ignore);
$str = trim($str);
$str = preg_replace("#[&].{2,7}[;]#sim", " ", $str);
$str = preg_replace("#[()°^!\"§\$%&/{(\[)\]=}?´`,;.:\-_\#'~+*]#", " ", $str);
$str = preg_replace("#\s+#sim", " ", $str);
$arraw = explode(" ", $str);
foreach($arraw as $v){
$v = trim($v);
if(strlen($v)<3 || in_array($v, $ignore_arr)) continue;
$arr[$v]++;
}
arsort($arr);
return array_keys( array_slice($arr, 0, $limit) );
}
$meta_keywords = implode(", ", top_words( strip_tags( $html_content ) ) );
?>
The problem is when your loop never increments $arr[$v], which results in the possibility of $arr not becoming defined. This is the reason for your error because then arsort() is given null as its argument - not an array.
The solution is to define $arr as an array before the loop for instances where $arr[$v]++; isn't executed.
function top_words($str, $limit=10, $ignore=""){
if(!$ignore) $ignore = "the of to and a in for is The that on said with be was by";
$ignore_arr = explode(" ", $ignore);
$str = trim($str);
$str = preg_replace("#[&].{2,7}[;]#sim", " ", $str);
$str = preg_replace("#[()°^!\"§\$%&/{(\[)\]=}?´`,;.:\-_\#'~+*]#", " ", $str);
$str = preg_replace("#\s+#sim", " ", $str);
$arraw = explode(" ", $str);
$arr = array(); // Defined $arr here.
foreach($arraw as $v){
$v = trim($v);
if(strlen($v)<3 || in_array($v, $ignore_arr)) continue;
$arr[$v]++;
}
arsort($arr);
return array_keys( array_slice($arr, 0, $limit) );
}
Came across an excellent code that words well for this:
<?php
function extract_keywords($str, $minWordLen = 3, $minWordOccurrences = 2, $asArray = false, $maxWords = 5, $restrict = true)
{
$str = str_replace(array("?","!",";","(",")",":","[","]"), " ", $str);
$str = str_replace(array("\n","\r"," "), " ", $str);
strtolower($str);
function keyword_count_sort($first, $sec)
{
return $sec[1] - $first[1];
}
$str = preg_replace('/[^\p{L}0-9 ]/', ' ', $str);
$str = trim(preg_replace('/\s+/', ' ', $str));
$words = explode(' ', $str);
// If we don't restrict tag usage, we'll remove common words from array
if ($restrict == false) {
$commonWords = array('a','able','about','above', 'get a list here http://www.wordfrequency.info','you\'ve','z','zero');
$words = array_udiff($words, $commonWords,'strcasecmp');
}
// Restrict Keywords based on values in the $allowedWords array
// Use if you want to limit available tags
if ($restrict == true) {
$allowedWords = array('engine','boeing','electrical','pneumatic','ice','pressurisation');
$words = array_uintersect($words, $allowedWords,'strcasecmp');
}
$keywords = array();
while(($c_word = array_shift($words)) !== null)
{
if(strlen($c_word) < $minWordLen) continue;
$c_word = strtolower($c_word);
if(array_key_exists($c_word, $keywords)) $keywords[$c_word][1]++;
else $keywords[$c_word] = array($c_word, 1);
}
usort($keywords, 'keyword_count_sort');
$final_keywords = array();
foreach($keywords as $keyword_det)
{
if($keyword_det[1] < $minWordOccurrences) break;
array_push($final_keywords, $keyword_det[0]);
}
$final_keywords = array_slice($final_keywords, 0, $maxWords);
return $asArray ? $final_keywords : implode(', ', $final_keywords);
}
$text = "Many systems that traditionally had a reliance on the pneumatic system have been transitioned to the electrical architecture. They include engine start, API start, wing ice protection, hydraulic pumps and cabin pressurisation. The only remaining bleed system on the 787 is the anti-ice system for the engine inlets. In fact, Boeing claims that the move to electrical systems has reduced the load on engines (from pneumatic hungry systems) by up to 35 percent (not unlike today’s electrically power flight simulators that use 20% of the electricity consumed by the older hydraulically actuated flight sims).";
echo extract_keywords($text);
// Advanced Usage
// $exampletext = "The quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog.";
// echo extract_keywords($exampletext, 3, 1, false, 5, false);
?>

Categories