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);
?>
Related
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.
I have a search String: $str (Something like "test"), a wrap string: $wrap (Something like "|") and a text string: $text (Something like "This is a test Text").
$str is 1 Time in $text. What i want now is a function that will wrap $str with the wrap defined in $wrap and output the modified text (even if $str is more than one time in $text).
But it shall not output the whole text but just 1-2 of the words before $str and then 1-2 of the words after $str and "..." (Only if it isn`t the first or last word). Also it should be case insensitive.
Example:
$str = "Text"
$wrap = "<span>|</span>"
$text = "This is a really long Text where the word Text appears about 3 times Text"
Output would be:
"...long <span>Text</span> where...word <span>Text</span> appears...times <span>Text</span>"
My Code (Obviusly doesnt works):
$tempar = preg_split("/$str/i", $text);
if (count($tempar) <= 2) {
$result = "... ".substr($tempar[0], -7).$wrap.substr($tempar[1], 7)." ...";
} else {
$amount = substr_count($text, $str);
for ($i = 0; $i < $amount; $i++) {
$result = $result.".. ".substr($tempar[$i], -7).$wrap.substr($tempar[$i+1], 0, 7)." ..";
}
}
If you have a tipp or a solution dont hesitate to let me know.
I have taken your approach and made it more flexible. If $str or $wrap changes you could have escaping issues within the regex pattern so I have used preg_quote.
Note that I added $placeholder to make it clearer, but you can use $placeholder = "|" if you don't like [placeholder].
function wrapInString($str, $text, $element = 'span') {
$placeholder = "[placeholder]"; // The string that will be replaced by $str
$wrap = "<{$element}>{$placeholder}</{$element}>"; // Dynamic string that can handle more than just span
$strExp = preg_quote($str, '/');
$matches = [];
$matchCount = preg_match_all("/(\w+\s+)?(\w+\s+)?({$strExp})(\s+\w+)?(\s+\w+)?/i", $text, $matches);
$response = '';
for ($i = 0; $i < $matchCount; $i++) {
if (strlen($matches[1][$i])) {
$response .= '...';
}
if (strlen($matches[2][$i])) {
$response .= $matches[2][$i];
}
$response .= str_replace($placeholder, $matches[3][$i], $wrap);
if (strlen($matches[4][$i])) {
$response .= $matches[4][$i];
}
if (strlen($matches[5][$i]) && $i == $matchCount - 1) {
$response .= '...';
}
}
return $response;
}
$text = "text This is a really long Text where the word Text appears about 3 times Text";
string(107) "<span>text</span> This...long <span>text</span> where...<span>text</span> appears...times <span>text</span>"
To make the replacement case insensitive you can use the i regex option.
If I understand your question correct, just a little bit of implode and explode magic needed
$text = "This is a really long Text where the word Text appears about 3 times Text";
$arr = explode("Text", $text);
print_r(implode('<span>Text</span>', $arr));
If you specifically need to render the span tags using HTML, just write it that way
$arr = explode("Text", $text);
print_r(implode('<span>Text</span>', $arr));
Use patern below to get your word and 1-2 words before and after
/((\w+\s+){1,2}|^)text((\s+\w+){1,2}|$)/i
demo
In PHP code it can be:
$str = "Text";
$wrap = "<span>|</span>";
$text = "This is a really long Text where the word Text appears about 3 times Text";
$temp = str_replace('|', $str, $wrap); // <span>Text</span>
// find patern and 1-2 words before and after
// (to make it casesensitive, delete 'i' from patern)
if(preg_match_all('/((\w+\s+){1,2}|^)text((\s+\w+){1,2}|$)/i', $text, $match)) {
$res = array_map(function($x) use($str, $temp) { return '... '.str_replace($str, $temp, $x) . ' ...';}, $match[0]);
echo implode(' ', $res);
}
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);
?>
i want to replace a char and want to put that character just after next char in php.
for example:
<?php
$exa = array("R" => "r", "A" => "a", "V" => "v", "I" => "i");
echo strtr("RAVI", $exa);
?> //displays "ravi" ok
i want to replace "V" with "v" and then want to put it after "I".
like this: "raiv"
I think this solution might interest you:
Function
function replaceAndMove($text, $replacements) {
$from = array_keys($replacements);
$to = array_values($replacements);
function fixFrom($s) {
return '/' . preg_quote($s, '/') . '(.|$)' . '/';
}
function fixTo($s) {
return '${1}' . $s;
}
$from_ready = array_map('fixFrom', $from);
$to_ready = array_map('fixTo', $to);
return preg_replace($from_ready, $to_ready, $text);
}
Test Case
$text = "abcdXefghXijklX----aFb~~~cMd";
$replacements = array(
'X' => 'x',
'F' => 'f',
'M' => 'm',
);
echo $text . '<br>';
echo replaceAndMove($text, $replacements);
Output
abcdXefghXijklX----aFb~~~cMd
abcdexfghixjkl-x---abf~~~cdm
Edit: Fixed problems with regex-special chars, such as . or ]
do the str_replace first, then use strlen, substr and the index of the character string to replace the last 2 spots if that is what you are trying to do. Because you can access a string like an array each characters $t[1] == e if the string was "test"
If you have a few "set" patterns you could just do this:
$find = array('RAVI',...,so on);
$replace = array('raiv',..., so on);
$input = 'RAVI';
echo str_replace($find, $replace, $input);
Just add more set pairs to the arrays for more replacements... If that's all you want.
Are you looking for something like this:
<?php
$string = "RAVIVL";
$replace_char = "v";
$string = strtolower($string);
$pos = array_keys(array_intersect(str_split($string),array($replace_char)));
foreach ($pos as $p) {
if (isset($string[$p+1])) {
$string[$p] = $string[$p+1];
$string[$p+1] = $replace_char;
}
}
echo $string;
?>
Swaps all occurrences o "v" with the following letter.
How can I make upper-case the first character of each word in a string accept a couple of words which I don't want to transform them, like - and, to, etc?
For instance, I want this - ucwords('art and design') to output the string below,
'Art and Design'
is it possible to be like - strip_tags($text, '<p><a>') which we allow and in the string?
or I should use something else? please advise!
thanks.
None of these are really UTF8 friendly, so here's one that works flawlessly (so far)
function titleCase($string, $delimiters = array(" ", "-", ".", "'", "O'", "Mc"), $exceptions = array("and", "to", "of", "das", "dos", "I", "II", "III", "IV", "V", "VI"))
{
/*
* Exceptions in lower case are words you don't want converted
* Exceptions all in upper case are any words you don't want converted to title case
* but should be converted to upper case, e.g.:
* king henry viii or king henry Viii should be King Henry VIII
*/
$string = mb_convert_case($string, MB_CASE_TITLE, "UTF-8");
foreach ($delimiters as $dlnr => $delimiter) {
$words = explode($delimiter, $string);
$newwords = array();
foreach ($words as $wordnr => $word) {
if (in_array(mb_strtoupper($word, "UTF-8"), $exceptions)) {
// check exceptions list for any words that should be in upper case
$word = mb_strtoupper($word, "UTF-8");
} elseif (in_array(mb_strtolower($word, "UTF-8"), $exceptions)) {
// check exceptions list for any words that should be in upper case
$word = mb_strtolower($word, "UTF-8");
} elseif (!in_array($word, $exceptions)) {
// convert to uppercase (non-utf8 only)
$word = ucfirst($word);
}
array_push($newwords, $word);
}
$string = join($delimiter, $newwords);
}//foreach
return $string;
}
Usage:
$s = 'SÃO JOÃO DOS SANTOS';
$v = titleCase($s); // 'São João dos Santos'
since we all love regexps, an alternative, that also works with interpunction (unlike the explode(" ",...) solution)
$newString = preg_replace_callback("/[a-zA-Z]+/",'ucfirst_some',$string);
function ucfirst_some($match)
{
$exclude = array('and','not');
if ( in_array(strtolower($match[0]),$exclude) ) return $match[0];
return ucfirst($match[0]);
}
edit added strtolower(), or "Not" would remain "Not".
How about this ?
$string = str_replace(' And ', ' and ', ucwords($string));
You will have to use ucfirst and loop through every word, checking e.g. an array of exceptions for each one.
Something like the following:
$exclude = array('and', 'not');
$words = explode(' ', $string);
foreach($words as $key => $word) {
if(in_array($word, $exclude)) {
continue;
}
$words[$key] = ucfirst($word);
}
$newString = implode(' ', $words);
I know it is a few years after the question, but I was looking for an answer to the insuring proper English in the titles of a CMS I am programming and wrote a light weight function from the ideas on this page so I thought I would share it:
function makeTitle($title){
$str = ucwords($title);
$exclude = 'a,an,the,for,and,nor,but,or,yet,so,such,as,at,around,by,after,along,for,from,of,on,to,with,without';
$excluded = explode(",",$exclude);
foreach($excluded as $noCap){$str = str_replace(ucwords($noCap),strtolower($noCap),$str);}
return ucfirst($str);
}
The excluded list was found at:
http://www.superheronation.com/2011/08/16/words-that-should-not-be-capitalized-in-titles/
USAGE: makeTitle($title);