Reputation: 81
I'm trying to do some sort of translator which would be able to keep text uppercase/lowercase.
Example:
Potato in the PLACE.
Potato in the pLAcE.
Potato in the place.
Potato in the Place.
I want to replace word place
with garden
while applying the original case in the replacement characters.
Potato in the GARDEN.
Potato in the gARdEn.
Potato in the garden.
Potato in the Garden.
It should also work with phrases.
Upvotes: 2
Views: 1160
Reputation: 47900
To make a multibyte-safe, full word replacement, use word boundaries when making an initial match with preg_replace_callback()
, then implement a "counter" variable to assist in synchronizing the replacement casing with the found word's casing.
This implementation avoids fumbling with excessive loops and multibyte function calls. The first regex will isolate full words. The second regex will read each letter of the match and simultaneously determine if it is an uppercase character or something else -- this dictates whether the corresponding replacement character should be made uppercase.
Code: (Demo)
$find = 'place'; // case is irrelevant to processing
$replace = 'garden'; // must be declared in all lowercase
echo preg_replace_callback(
'#\b' . preg_quote($find) . '\b#ui',
function ($word) use ($replace) {
$i = 0;
return preg_replace_callback(
'#(\p{Lu})|.#su',
function ($char) use ($replace, &$i) {
$newChar = mb_substr($replace, $i++, 1);
return isset($char[1]) ? mb_strtoupper($newChar) : $newChar;
},
$word[0]
) . mb_substr($replace, $i); // append remaining chars unaltered
},
'Place replacements in their proper plACe without being complacent; use word boundaries.'
);
Output:
Garden replacements in their proper gaRDen without being complacent; use word boundaries.
Upvotes: 1
Reputation: 81
So I managed to create my own function in the end. Thanks for help and inspiration though.
function replaceWithCase($source, $replacement, $string, $pos = 0) {
while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {
$substr = mb_substr($string, $pos, strlen($source));
$remaining = mb_substr($string, $pos + strlen($source));
if (ctype_upper($substr)) {
$string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
continue;
}
$substrParts = preg_split('//u', $substr, null, PREG_SPLIT_NO_EMPTY);
$replaceParts = preg_split('//u', $replacement, null, PREG_SPLIT_NO_EMPTY);
$newWord = '';
foreach ($replaceParts as $k => $rp) {
if (array_key_exists($k,$substrParts))
$newWord .= ctype_upper($substrParts[$k]) ? mb_strtoupper($rp) : mb_strtolower($rp);
else
$newWord .= $rp;
}
$string = substr_replace($string,$newWord,$pos,strlen($source));
$pos = $pos + strlen($source);
}
return $string;
}
echo replaceWithCase("place", "garden", "Potato is jumping all over the PLACE");
echo "<br>";
echo replaceWithCase("jumping", "running", "Potato is jumping all over the pLAcE");
echo "<br>";
echo replaceWithCase("jumping", "cry", "Potato is jumping all over the place");
echo "<br>";
echo replaceWithCase("all", "", "Potato is jumping all over the Place");
echo "<br>";
echo replaceWithCase(" ", ";", "Potato is jumping all over the Place", 10);
echo "<br>";
Output:
Potato is jumping all over the GARDEN
Potato is running all over the pLAcE
Potato is cry all over the place
Potato is jumping over the Place
Potato is jumping;all;over;the;Place
Upvotes: 1
Reputation: 821
Use "stripos" php function
$str = 'Potato is jumping all over the pLAcEs.';
$str_new = "garden";
$str1 = str_split($str_new);
$pos = stripos($str,'places');
$string = substr($str,$pos,6);
$extrct = str_split($string);
$var = '';
foreach ($extrct as $key => $value) {
if(ctype_upper($value))
{
$var .= strtoupper($str1[$key]);
}else{
$var .= strtolower($str1[$key]);
}
}
$new_string = str_replace($string, $var, $str);
echo $new_string; //Potato is jumping all over the gARdEn.
Upvotes: -1
Reputation: 11
function stringReplace($findStr, $replaceStr, $str)
{
$isLowerStr = true;
for($i=0; $i<strlen($findStr); $i++){
if(ord($findStr[$i]) >= 97 && ord($findStr[$i])<=122){
if(ord($replaceStr[$i]) >= 65 && ord($replaceStr[$i])<=96){
$replaceStr[$i] = strtolower($replaceStr[$i]);
}else{
$replaceStr[$i] = $replaceStr[$i];
}
}else{
$isLowerStr = false;
$replaceStr[$i] = strtoupper($replaceStr[$i]);
}
}
if($isLowerStr == false){
if(strlen($replaceStr) > strlen($findStr)){
for($i=0;$i<(strlen($replaceStr)-strlen($findStr));$i++){
if(strtoupper($findStr) == $findStr){
$replaceStr[strlen($findStr)+$i] = strtoupper($replaceStr[strlen($findStr)+$i]);
}else{
$replaceStr[strlen($findStr)+$i] = strtolower($replaceStr[strlen($findStr)+$i]);
}
}
}
}
echo str_replace($findStr, $replaceStr, $str);die;
}
$findStr = 'Place';
$replaceStr = 'garden';
echo stringReplace($findStr, $replaceStr, 'Potato is jumping all over the '.$findStr.'.');
Upvotes: 1
Reputation: 9123
I've created a function that will replace the word for you and keep the cases.
function replaceWithCase($source, $replacement, $string) {
// Does the string contain the source word?
if (strpos($string, $source) === false) {
return false;
}
// If everything is uppercase, return the replacement fully uppercase
if (ctype_upper($source)) {
return str_replace($source, strtoupper($replacement));
}
// Set an array to work with
$characters = array();
// Split the source into characters
$sourceParts = explode('', $source);
// Loop throug the characters and set the case
foreach ($sourceParts as $k => $sp) {
if (ctype_upper($sp)) {
$characters[$k] = true;
} else {
$characters[$k] = false;
}
}
// Split the replacement into characters
$replacementParts = explode('', $replacement);
// Loop through characters and compare their case type
foreach ($replacementParts as $k => $rp) {
if (array_key_exists($k, $characters) && $characters[$k] === true) {
$newWord[] = strtoupper($rp);
} else {
$newWord[] = strtolower($rp);
}
}
return substr_replace($source, implode('', $newWord), $string);
}
// usage
echo replaceWithCase('AppLes', 'bananas', 'Comparing AppLes to pears');
Note: it is untested and might need some tweaking
Upvotes: 2