PHP - 正常替换字符串并仅反转一次

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

每个单词只需替换一次,反之亦然。为此,我使用了不起作用的代码,并且找不到我的问题的答案。

输入:

hello w1 w2 w12 new1 new12 new2

预期输出:

hello new1 new2 w12 w1 new12 w2

我需要在文本中替换单词/短语。

w1 替换为 new1

w12不变

w2 替换为 new2

new1 替换为 w1

新12不变

new2 替换为 w2

当然我的波斯语文字

我的代码是:

$string="hello w1 w2 w12 new1 new12 new2";

$fword= array("w1","w2");
$lword= array("new1","new2");

$cnt=0;
$string=str_replace($fword,$lword,$string,$cnt);
$string=str_replace($lword,$fword,$string,$cnt);
echo "<h2>Change in string: $cnt <br> New String: $string </h2>";

但是这是错误的

我也使用这个代码:

$string="hello w1 w2 w12 new1 new12 new2";

$fword= array("w1","w2","new1","new2");
$lword= array("new1","new2","w1","w2");

$cnt=0;
$string=str_replace($fword,$lword,$string,$cnt);
echo "<h2>Change in string: $cnt <br> New String: $string </h2>";
php replace str-replace replacewith
4个回答
2
投票

您应该使用 preg_replace。告诉它检查空格或字符串开头或结尾

(^|.*\s)
(\s.*|$)
以避免替换部分匹配项。

$string="hello w1 w2 w12 new1 new12 new2";

$replacements = array(
    "w1" => "new1",
    "w2" => "new2",
    "new1" => "w1",
    "new2" => "w2"
);

foreach ($replacements as $from=>$to) {
    $string = preg_replace(
                '/(^|.*\s)'.preg_quote($from).'(\s.*|$)/',
                '\1'.preg_quote($to).'\2', 
                $string);
}

echo $string;

如果只需要替换第一个出现的情况,您也可以将此函数的第四个参数限制为 1。

更新:详细说明

(^|.*\s)
:第一个匹配组:字符串开始,或字符串开头后跟一个空格。

preg_quote($from)
:要替换的字符串。它被引用以支持所有类型的字符。 preg_quote() 将转义所有字符,以免干扰正则表达式控制代码。还处理 Unicode 字符。

(\s.*|$)
:第二个匹配组:字符串或空格结尾,后跟字符串的其余部分。

'\1'.preg_quote($to).'\2'
:替代品。第一组 + 新字符串 + 第二组。

更新2:

摆脱了代码中不必要的组并添加了转义以更普遍地适用于所有类型的输入。


2
投票

我知道这是一篇很长的文章,但我已尽力完成它。

PHP 代码演示

<?php
ini_set("display_errors", 1);

echo $string="hello w1 w2 w12 new1 new12 new2";
$fword= array("w1","w2","new1","new2");
$lword= array("new1","new2","w1","w2");

//---------Working----------->
$replacement=  array_combine($fword, $lword);
$totrimOffsets=array();
$indexes=findIndexes($fword);
$string=preg_replace("/\~\~{1,}/", "~~", $string);
$newString=replace();
//--------------------------->
echo PHP_EOL;
echo $newString;
function findIndexes($array)
{
    global $totrimOffsets,$string,$replacement;
    $indexes=array();
    foreach($array as $element)
    {
        preg_match_all("/\b$element\b/i", $string,$matches,PREG_OFFSET_CAPTURE);
        if(isset($matches[0]) && count($matches[0])>0)
        {
            foreach($matches[0] as $matchData)
            {
                $indexes[$element][]=array("element"=>$element,"offset"=>$matchData[1],"length"=>  strlen($element));
                $totrimOffsets[]=$matchData[1].",".($matchData[1]+strlen($element)-1).",".$element.",".$replacement[$element];
                $string=  substr_replace($string, getSpecialChars(strlen($element)), $matchData[1],strlen($element));
            }
        }
    }
    sort($totrimOffsets,SORT_NUMERIC);
    return $indexes;
}
function replace()
{
    global $string,$totrimOffsets,$indexes;
    $stringArray=explode("~~",$string);
    $newString="";
    foreach($stringArray as $key => $value)
    {
        $newString.=$value;
        if(isset($totrimOffsets[$key]))
        {
            $newString.=explode(",",$totrimOffsets[$key])[3];
        }
    }
    return $newString;
}
function getSpecialChars($length)
{
    $dummyString="";
    for($x=0;$x<$length;$x++)
    {
        $dummyString.="~";
    }
    return $dummyString;
}

2
投票

您可以使用

strtok
对字符串进行标记。

然后在反向循环中检查标记,如果截断的标记在允许的单词列表中,则替换它(您可以有一个映射数组,如 ["W1" => "E1", ...])。如果这样的词已经被替换了,那就更进一步吧


0
投票

为了确保您的脚本仅替换整个单词,请在所有搜索字符串的管道集合周围使用单词边界。在

preg_replace_callback()
的回调中,搜索映射数组以查找匹配子字符串的适当替换值。

此技术不会替换替换,因为输入字符串仅被遍历一次。

代码:(演示

$string = 'hello w1 w2 w12 new1 new12 new2';

$map = [
    'w1' => 'new1',
    'w2' => 'new2',
    'new1' => 'w1',
    'new2' => 'w2',
];

$subpattern = implode('|', array_map('preg_quote', array_keys($map)));

echo preg_replace_callback(
         '#\b(?:' . $subpattern . ')\b#u',
         fn($m) => $map[$m[0]] ?? $m[0],
         $string
     );
// hello new1 new2 w12 w1 new12 w2

如果单词边界不适用于您真正的波斯语内容,那么您需要提供更好的示例数据,以便可以制作定制的模式。

© www.soinside.com 2019 - 2024. All rights reserved.