替换字符串并在替换中保留原始字符串的大小写

问题描述 投票:0回答:6

我正在尝试做某种能够保持文本大写/小写的翻译器。 我也需要在 PHP 字符串和 MySQL 查询中替换它。

示例:

Potato in the PLACE.
Potato in the pLAcE.
Potato in the place.
Potato in the Place.

我想用

place
替换单词
garden
,同时在替换字符中应用原始大小写。

Potato in the GARDEN.
Potato in the gARdEn.
Potato in the garden.
Potato in the Garden.

它也应该适用于短语。

php string replace case-sensitive
6个回答
2
投票

我创建了一个函数,可以为您替换单词并保留大小写。

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');

注意:它未经测试,可能需要一些调整


1
投票
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.'.');

1
投票

所以我最终成功创建了自己的函数。不过,感谢您的帮助和灵感。

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>";

输出:

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

0
投票

感谢@LadaB - 这是一个非常有用的功能,但它也取代了部分单词匹配。有时您可能想要这个,但在其他情况下您不会,例如,如果您有:

$source = 'mom';
$replacement = 'mum'; // british spelling of "mom"
$string = 'Be in the moment with your Mom.';

您会得到:“与您的妈妈一起进入mument。”

因此,我添加了一个选项来使匹配“仅整个单词”。

我发现了另一个问题,即多字节字符会在大写结束的位置发生变化,这似乎可以通过更改来解决。

mb_substr
substr

我还删除了未使用的:

$remaining = substr($string, $pos + strlen($source));

我最后更改了 strlen 计算以使用

$replacement
以避免“ValueError: strpos(): Argument #3 ($offset) must be contains in argument #1 ($haystack)”异常是替换的单词是 at /靠近字符串末尾。

我最新的(我认为完全有效)版本是:

function replaceWithCase($source, $replacement, $string, $wholeWordOnly = false) {

    $pos = 0;

    while (($pos = strpos(strtolower($string), strtolower($source), $pos))!== false) {

        if($wholeWordOnly) {
            preg_match("/\b".$string[$pos]."/", $string[($pos-1)] . $string[$pos], $start);
            preg_match("/".$string[($pos+strlen($source)-1)]."\b/", $source . $string[($pos+strlen($source))], $end);
        }

        if(($wholeWordOnly && $start && $end) || !$wholeWordOnly) {

            $substr = substr($string, $pos, strlen($source));

            if (ctype_upper($substr)) {
                $string = substr_replace($string,strtoupper($replacement),$pos,strlen($source));
                continue;
            }

            $substrParts = preg_split('//u', $substr, -1, PREG_SPLIT_NO_EMPTY);
            $replaceParts = preg_split('//u', $replacement, -1, 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($replacement);

    }

    return $string;
}

希望对您或其他人有帮助。


0
投票

要进行多字节安全的全字替换,请在与

preg_replace_callback()
进行初始匹配时使用字边界,然后实现“计数器”变量以帮助将替换大小写与找到的单词的大小写同步。

此实现避免了过多的循环和多字节函数调用。第一个正则表达式将隔离完整的单词。第二个正则表达式将读取匹配的每个字母,并同时确定它是大写字符还是其他字符——这决定了相应的替换字符是否应设为大写。

代码:(演示

$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.'
     );

输出:

Garden replacements in their proper gaRDen without being complacent; use word boundaries.

-1
投票
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.
© www.soinside.com 2019 - 2024. All rights reserved.