i want : He had XXX to have had it. Or : He had had to have XXX it.
$string = "He had had to have had it.";
echo preg_replace('/had/', 'XXX', $string, 1);
output :
He XXX had to have had it.
in the case of, 'had' is replaced is the first.
I want to use the second and third. not reading from the right or left, what "preg_replace" can do it ?
$string = "He had had to have had it.";
$replace = 'XXX';
$counter = 0; // Initialise counter
$entry = 2; // The "found" occurrence to replace (starting from 1)
echo preg_replace_callback(
'/had/',
function ($matches) use ($replace, &$counter, $entry) {
return (++$counter == $entry) ? $replace : $matches[0];
},
$string
);
Try this:
<?php
function my_replace($srch, $replace, $subject, $skip=1){
$subject = explode($srch, $subject.' ', $skip+1);
$subject[$skip] = str_replace($srch, $replace, $subject[$skip]);
while (($tmp = array_pop($subject)) == '');
$subject[]=$tmp;
return implode($srch, $subject);
}
$test ="He had had to have had it.";;
echo my_replace('had', 'xxx', $test);
echo "<br />\n";
echo my_replace('had', 'xxx', $test, 2);
?>
Look at CodeFiddle
Probably not going to win any concours d'elegance with this, but very short:
$string = "He had had to have had it.";
echo strrev(preg_replace('/dah/', 'XXX', strrev($string), 1));
Try this
Solution
function generate_patterns($string, $find, $replace) {
// Make single statement
// Replace whitespace characters with a single space
$string = preg_replace('/\s+/', ' ', $string);
// Count no of patterns
$count = substr_count($string, $find);
// Array of result patterns
$solutionArray = array();
// Require for substr_replace
$findLength = strlen($find);
// Hold index for next replacement
$lastIndex = -1;
// Generate all patterns
for ( $i = 0; $i < $count ; $i++ ) {
// Find next word index
$lastIndex = strpos($string, $find, $lastIndex+1);
array_push( $solutionArray , substr_replace($string, $replace, $lastIndex, $findLength));
}
return $solutionArray;
}
$string = "He had had to have had it.";
$find = "had";
$replace = "yz";
$solutionArray = generate_patterns($string, $find, $replace);
print_r ($solutionArray);
Output :
Array
(
[0] => He yz had to have had it.
[1] => He had yz to have had it.
[2] => He had had to have yz it.
)
I manage this code try to optimize it.
Related
I want to do a str_replace() but only at the Nth occurrence.
Inputs:
$originalString = "Hello world, what do you think of today's weather";
$findString = ' ';
$nthOccurrence = 8;
$newWord = ' beautiful ';
Desired Output:
Hello world, what do you think of today's beautiful weather
Here is a tight little regex with \K that allows you to replace the nth occurrence of a string without repeating the needle in the pattern. If your search string is dynamic and might contain characters with special meaning, then preg_quote() is essential to the integrity of the pattern.
If you wanted to statically write the search string and nth occurrence into your pattern, it could be:
(?:.*?\K ){8}
or more efficiently for this particular case: (?:[^ ]*\K ){8}
\K tells the regex pattern to "forget" any previously matched characters in the fullstring match. In other words, "restart the fullstring match" or "Keep from here". In this case, the pattern only keeps the 8th space character.
Code: (Demo)
function replaceNth(string $input, string $find, string $replacement, int $nth = 1): string {
$pattern = '/(?:.*?\K' . preg_quote($find, '/') . '){' . $nth . '}/';
return preg_replace($pattern, $replacement, $input, 1);
}
echo replaceNth($originalString, $findString, $newWord, $nthOccurrence);
// Hello world, what do you think of today's beautiful weather
Another perspective on how to grapple the asked question is: "How to insert a new string after the nth instance of a search string?" Here is a non-regex approach that limits the explosions, prepends the new string to the last element then re-joins the elements. (Demo)
$originalString = "Hello world, what do you think of today's weather";
$findString = ' ';
$nthOccurrence = 8;
$newWord = 'beautiful '; // notice that leading space was removed
function insertAfterNth($input, $find, $newString, $nth = 1) {
$parts = explode($find, $input, $nth + 1);
$parts[$nth] = $newString . $parts[$nth];
return implode($find, $parts);
}
echo insertAfterNth($originalString, $findString, $newWord, $nthOccurrence);
// Hello world, what do you think of today's beautiful weather
I found an answer here - https://gist.github.com/VijayaSankarN/0d180a09130424f3af97b17d276b72bd
$subject = "Hello world, what do you think of today's weather";
$search = ' ';
$occurrence = 8;
$replace = ' nasty ';
/**
* String replace nth occurrence
*
* #param type $search Search string
* #param type $replace Replace string
* #param type $subject Source string
* #param type $occurrence Nth occurrence
* #return type Replaced string
*/
function str_replace_n($search, $replace, $subject, $occurrence)
{
$search = preg_quote($search);
echo preg_replace("/^((?:(?:.*?$search){".--$occurrence."}.*?))$search/", "$1$replace", $subject);
}
str_replace_n($search, $replace, $subject, $occurrence);
$originalString = "Hello world, what do you think of today's weather";
$findString = ' ';
$nthOccurrence = 8;
$newWord = ' beautiful ';
$array = str_split($originalString);
$count = 0;
$num = 0;
foreach ($array as $char) {
if($findString == $char){
$count++;
}
$num++;
if($count == $nthOccurrence){
array_splice( $array, $num, 0, $newWord );
break;
}
}
$newString = '';
foreach ($array as $char) {
$newString .= $char;
}
echo $newString;
I would consider something like:
function replaceNth($string, $substring, $replacement, $nth = 1){
$a = explode($substring, $string); $n = $nth-1;
for($i=0,$l=count($a)-1; $i<$l; $i++){
$a[$i] .= $i === $n ? $replacement : $substring;
}
return join('', $a);
}
$originalString = 'Hello world, what do you think of today\'s weather';
$test = replaceNth($originalString, ' ', ' beautiful ' , 8);
$test2 = replaceNth($originalString, 'today\'s', 'good');
First explode a string by parts, then concatenate the parts together and with search string, but at specific number concatenate with replace string (numbers here start from 0 for convenience):
function str_replace_nth($search, $replace, $subject, $number = 0) {
$parts = explode($search, $subject);
$lastPartKey = array_key_last($parts);
$result = '';
foreach($parts as $key => $part) {
$result .= $part;
if($key != $lastPartKey) {
if($key == $number) {
$result .= $replace;
} else {
$result .= $search;
}
}
}
return $result;
}
Usage:
$originalString = "Hello world, what do you think of today's weather";
$findString = ' ';
$nthOccurrence = 7;
$newWord = ' beautiful ';
$result = str_replace_nth($findString, $newWord, $originalString, $nthOccurrence);
am trying to replace a word in a string BUT i want to get the word found in the function and replace it with a word with stars with the exact length ?
Is this possible or do i need to do this in some other way ?
$text = "Hello world, its 2018";
$words = ['world', 'its'];
echo str_replace($words, str_repeat("*", count(FOUND) ), $text);
You could use a regular expression to do that :
$text = preg_replace_callback('~(?:'.implode('|',$words).')~i', function($matches){
return str_repeat('*', strlen($matches[0]));
}, $text);
echo $text ; // "Hello *****, *** 2018"
You also could secure this using preg_quote before to use preg_replace_callback() :
$words = array_map('preg_quote', $words);
EDIT : The following code is another way, that use a foreach() loop, but prevent unwanted behaviors (replacing part of words), and allows multi-bytes characters:
$words = ['foo', 'bar', 'bôz', 'notfound'];
$text = "Bar&foo; bAr notfoo, bôzo bôz :Bar! (foo), notFOO and NotBar or 'bar' foo";
$expt = "***&***; *** notfoo, bôzo *** :***! (***), notFOO and NotBar or '***' ***";
foreach ($words as $word) {
$text = preg_replace_callback("~\b$word\b~i", function($matches) use ($word) {
return str_ireplace($word, str_repeat('*', mb_strlen($word)), $matches[0]);
}, $text);
}
echo $text, PHP_EOL, $expt ;
Another approach:
$text = "Hello world, its 2018";
$words = ['world', 'its'];
$f = function($value) { return str_repeat("*", strlen($value)) ; } ;
$replacement = array_map($f, $words);
echo str_replace($words, $replacement, $text);
You can try this :
$text = "Hello world, its 2018";
$words = ['world', 'its'];
// Loop through your word array
foreach ($words as $word) {
$length = strlen($word); // length of the word you want to replace
$star = str_repeat("*", $length); // I build the new string ****
$text = str_replace($word, $star, $text); // I replace the $word by the new string
}
echo $text; // Hello *****, *** 2018
Is it what you are looking for?
You can go like this..
$text = "Hello crazy world, its 2018";
$words = ['world', 'its'];
array_walk($words,"replace_me");
function replace_me($value,$key)
{
global $text;
$text = str_replace($value,str_repeat("*",strlen($value)),$text);
}
echo $text;
$text = "Hello world, its 2018";
$words = ['world', 'its'];
// Loop through your word array
foreach ($words as $word) {
$length = strlen($word); // length of the word you want to replace
$star = str_repeat("*", $length); // I build the new string ****
$text = str_replace($word, $star, $text); // I replace the $word by the new string
}
echo $text; // Hello *****, *** 2018
I need to edit all odd words to upper case.
Here is sample of imput string:
very long string with many words
Expected output:
VERY long STRING with MANY words
I have this code, but it seams to me, that I can do it in better way.
<?php
$lines = file($_FILES["fname"]["tmp_name"]);
$pattern = "/(\S[\w]*)/";
foreach($lines as $value)
{
$words = NULL;
$fin_str = NULL;
preg_match_all($pattern, $value, $matches);
for($i = 0; $i < count($matches[0]); $i = $i + 2){
$matches[0][$i] = strtoupper($matches[0][$i]);
$fin_str = implode(" ", $matches[0]);
}
echo $fin_str ."<br>";
P.S. I need to use only preg_match function.
Here's a preg_replace_callback example:
<?php
$str = 'very long string with many words';
$newStr = preg_replace_callback('/([^ ]+) +([^ ]+)/',
function($matches) {
return strtoupper($matches[1]) . ' ' . $matches[2];
}, $str);
print $newStr;
// VERY long STRING with MANY words
?>
You only need to match the repeating pattern: /([^ ]+) +([^ ]+)/, a pair of words, then preg_replace_callback recurses over the string until all possible matches are matched and replaced. preg_replace_callback is necessary to call the strtoupper function and pass the captured backreference to it.
Demo
If you have to use regular expressions, this should get you started:
$input = 'very long string with many words';
if (preg_match_all('/\s*(\S+)\s*(\S+)/', $input, $matches)) {
$words = array();
foreach ($matches[1] as $key => $odd) {
$even = isset($matches[2][$key]) ? $matches[2][$key] : null;
$words[] = strtoupper($odd);
if ($even) {
$words[] = $even;
}
}
echo implode(' ', $words);
}
This will output:
VERY long STRING with MANY words
You may don't need regex simply use explode and concatenate the string again:
<?php
function upperizeEvenWords($str){
$out = "";
$arr = explode(' ', $str);
for ($i = 0; $i < count($arr); $i++){
if (!($i%2)){
$out .= strtoupper($arr[$i])." ";
}
else{
$out .= $arr[$i]." ";
}
}
return trim($out);
}
$str = "very long string with many words";
echo upperizeEvenWords($str);
Checkout this DEMO
I have this string...
$text = "1|2|1400|34|A|309|Frank|william|This|is|the|line|here|"
How do I replace all the occurrences of | with " " after the 8th occurrence of | from the beginning of the string?
I need it look like this, 1|2|1400|34|A|309|Frank|william|This is the line here
$find = "|";
$replace = " ";
I tried
$text = preg_replace(strrev("/$find/"),strrev($replace),strrev($text),8);
but its not working out so well. If you have an idea please help!
You can use:
$text = '1|2|1400|34|A|309|Frank|william|This|is|the|line|here|';
$repl = preg_replace('/^([^|]*\|){8}(*SKIP)(*F)|\|/', ' ', $text);
//=> 1|2|1400|34|A|309|Frank|william|This is the line here
RegEx Demo
Approach is to match and ignore first 8 occurrences of | using ^([^|]*\|){8}(*SKIP)(*F) and the replace each | by space.
You can use explode()
$text = "1|2|1400|34|A|309|Frank|william|This|is|the|line|here|";
$arr = explode('|', $text);
$result = '';
foreach($arr as $k=>$v){
if($k == 0) $result .= $v;
else $result .= ($k > 7) ? ' '.$v : '|'.$v;
}
echo $result;
You could use the below regex also and replace the matched | with a single space.
$text = '1|2|1400|34|A|309|Frank|william|This|is|the|line|here|';
$repl = preg_replace('~(?:^(?:[^|]*\|){8}|(?<!^)\G)[^|\n]*\K\|~', ' ', $text);
DEMO
<?php
$text = "1|2|1400|34|A|309|Frank|william|This|is|the|line|here|";
$texts = explode( "|", $text );
$new_text = '';
$total_words = count( $texts );
for ( $i = 0; $i < $total_words; $i++)
{
$new_text .= $texts[$i];
if ( $i <= 7 )
$new_text .= "|";
else
$new_text .= " ";
}
echo $new_text;
?>
The way to do that is:
$text = "1|2|1400|34|A|309|Frank|william|This|is|the|line|here|";
$arr = explode('|', $text, 9);
$arr[8] = strtr($arr[8], array('|'=>' '));
$result = implode('|', $arr);
echo $result;
Example without regex:
$text = "1|2|1400|34|A|309|Frank|william|This|is|the|line|here|";
$array = str_replace( '|', ' ', explode( '|', $text, 9 ) );
$text = implode( '|', $array );
str_replace:
If subject is an array, then the search and replace is performed with
every entry of subject, and the return value is an array as well.
explode:
If limit is set and positive, the returned array will contain a
maximum of limit elements with the last element containing the rest of
string.
I have got a function from Google to clean my paragraph in sentence case.
I want to modify this function such that it converts more than 2 new line character to newline. Else it converts all new line characters in space. So I would have it in paragraph format. Here it's converting all new line character to space.
It's converting in proper sentence case. But, In case If I found single word having first word as capital then I need function to ignore that. As Sometimes, if there would be any noun It needs to be capital. We can't change it small case. Else if noun and it is having more than 2 capital characters other than first character than convert it to lower case.
Like -> Noun => Noun but NoUn => noun. Means I want if other than first character is capital than it convert it two lower case Else it keep it in same format.
function sentence_case($string) {
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
//$new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
$new_string = clean_spaces($new_string);
$new_string = m_r_e_s($new_string);
return trim($new_string);
}
function sentence_case($str) {
$cap = true;
$ret='';
for($x = 0; $x < strlen($str); $x++){
$letter = substr($str, $x, 1);
if($letter == "." || $letter == "!" || $letter == "?"){
$cap = true;
}elseif($letter != " " && $cap == true){
$letter = strtoupper($letter);
$cap = false;
}
$ret .= $letter;
}
return $ret;
}
This will preserve existing proper noun capitals, acronyms and abbreviations.
This should do it:
function sentence_case($string) {
// Protect the paragraphs and the caps
$parDelim = "/(\n+\r?)/";
$string = preg_replace($parDelim, "#PAR#", $string);
$string = preg_replace("/\b([A-Z])/", "#$1#", $string);
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
//$new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
$new_string = clean_spaces($new_string);
$new_string = m_r_e_s($new_string);
// Restore the paragraphs and the caps
$new_string = preg_replace("#PAR#", PHP_EOL, $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
return trim($new_string);
}
It works by identifying the items you want to protect (paragraph & first cap) and marking it with a string that you can then replace back when you are done. The assumption is that you don't already have #PAR# and #A-Z# in the string. You can use whatever you want to use for the paragraph delimiter afterwards if you want to force a certain type of line ending or several lines in between.
Slightly modifying Sylverdrag's function, I got something that is working well for me. This version works for every messed-up sentence I've thrown at it so far :)
function sentence_case($string) {
$string = strtolower($string); // ADDED THIS LINE
// Protect the paragraphs and the caps
$parDelim = "/(\n+\r?)/";
$string = preg_replace($parDelim, "#PAR#", $string);
$string = preg_replace("/\b([A-Z])/", "#$1#", $string);
$sentences = preg_split('/([.?!]+)/', $string, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$new_string = '';
foreach ($sentences as $key => $sentence) {
$new_string .= ($key & 1) == 0?
ucfirst(strtolower(trim($sentence))) :
$sentence.' ';
}
$new_string = preg_replace("/\bi\b/", "I", $new_string);
// GOT RID OF THESE LINES
// $new_string = preg_replace("/\bi\'\b/", "I'", $new_string);
// $new_string = clean_spaces($new_string);
// $new_string = m_r_e_s($new_string);
// Restore the paragraphs and the caps
$new_string = preg_replace("#PAR#", PHP_EOL, $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
$new_string = preg_replace("/#([A-Z])#/", "$1", $new_string);
preg_match('/#(.*?)#/', $new_string, $match); // MODIFIED THIS LINE TO USE (.*?)
return trim($new_string);
}
$string = "that IS it!! YOU and i are Totally DONE hanging out toGether... like FOREveR DUDE! i AM serious. a good FRIEND would NOT treAT me LIKE you dO. it Seems, howEVER, THAT you ARE not ONE of tHe GOOD ONEs.";
echo "<b>String 1:</b> " . $string . "<br><b>String 2:</b> " . sentence_case($string);
PHP Sandbox
:) :)