求助,字符串替换问题

有一段文本是这样的 你现在是一位优秀的写作专家,在写作时会自主的选择和运用各种写作技巧、写作风格,或是引用名言名句。 我现在想请你帮忙写一份{1}。主要内容为:"{2}"。写作的字数大概为{4}字。 写作额外要求(如果没写要求则没有额外要求):{3} 其中的{1}…{4}会被用户输入的内容替换。
现在用户输入了一段这样的文本 你现在是一位优秀的写作专家,在写作时会自主的选择和运用各种写作技巧、写作风格,或是引用名言名句。 我现在想请你帮忙写一份小说中人物介绍:。主要内容为:"第一章苏乐醉酒后睡了个陌生男人,......决绝和坚定"。写作的字数大概为1000字。 写作额外要求(如果没写要求则没有额外要求):小说中人物介绍:。 我应该怎么把这段文本中用户输入的部分分别加上一个 span 标签呢?


大家的评论我都看到了,实现上当然可以拿到用户的输入直接加上 span 标签,或者记录好用户的输入,在需要的时候进行替换。但是我目前的现状是用户的输入已经是日志保存在表里了,我也不想动这块的业务逻辑。要将用户的输入展示一下只是后台的一个小功能。

下面是我实现的两种方案:
一:

function promptTranslate($prompt, $user_input)
{
    preg_match_all('/({\d+})/', $prompt, $matches);
    if (empty($matches[0])) {
        return $user_input;
    }
    $separator = '|';
    $matches   = $matches[0];
    for ($i = 0; $i < count($matches); $i++) {
        $prompt = str_replace($matches[$i], $separator, $prompt);
    }
    $sections = explode($separator, $prompt);

    foreach ($sections as $section) {
        $user_input = str_replace($section, $separator, $user_input);
    }
    $inputs = explode($separator, $user_input);
    $inputs = array_values(array_filter($inputs));
    foreach ($inputs as &$input) {
        $input = "<span class='bg-success'>{$input}</span>";
    }
    $result = '';
    foreach ($sections as $key => $section) {
        $temp   = $inputs[$key] ?? '';
        $result .= $section . $temp;
    }
    return $result;
}

二:

function promptTranslateV2($prompt, $user_input)
{
    preg_match_all('/({\d+})/', $prompt, $matches);
    if (empty($matches[0])) {
        return $user_input;
    }
    $separator = '';
    $matches   = $matches[0];
    for ($i = 0; $i < count($matches); $i++) {
        $prompt = str_replace($matches[$i], $separator, $prompt);
    }

    $result = '';
    $same   = true;
    for ($i = $j = 0; $i < mb_strlen($user_input); $i++) {
        $ch_p = mb_substr($prompt, $j, 1);
        $ch_u = mb_substr($user_input, $i, 1);
        if (!$ch_p) {
            $result .= $ch_u;
            continue;
        }
        if ($ch_u == $ch_p) {
            if (!$same) {
                $result .= '</span>';
            }
            $j++;
            $same = true;
        } else {
            if ($same) {
                $result .= "<span class='bg-success'>";
            }
            $same = false;
        }
        $result .= $ch_u;
    }
    return $result;
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 12

正则表达式匹配吧

9个月前 评论

不大明白, 替换前加上不就可了?

9个月前 评论

用户输入部分是模板变量对应的文本,能够拿到吧,直接套个span标签不就行了

9个月前 评论
瀚海栏杆 (楼主) 9个月前
$str = 'aaaa/%sddddddd/%s'
sprintf($str , 'a', 'b');
9个月前 评论
瀚海栏杆 (楼主) 9个月前

看你提问的描述怎么和你下面的评论完全是两码事啊?

也就是说你现在是有一个模板, 然后和一个完整的用户输入(换句话说,用户输入实际上已经是套用了模板的了,而不是填占位词),你的目的是想要提取出除模板外的用户输入的占位词部分?

在上面的例子里面,你就是要依次提取出下面这些内容?然后给这些内容包一个 span ?

  • 小说中人物介绍:
  • 第一章苏乐醉酒后睡了个陌生男人,……决绝和坚定
  • 1000
  • 小说中人物介绍:

试着简单的实现了一下,但是也可能存在一些问题,如果用户输入中存在的对应的关键字,也可能会被识别到。

$str1 = '你现在是一位优秀的写作专家,在写作时会自主的选择和运用各种写作技巧、写作风格,或是引用名言名句。 我现在想请你帮忙写一份{1}。主要内容为:"{2}"。写作的字数大概为{4}字。 写作额外要求(如果没写要求则没有额外要求):{3}';
$str2 = '你现在是一位优秀的写作专家,在写作时会自主的选择和运用各种写作技巧、写作风格,或是引用名言名句。 我现在想请你帮忙写一份小说中人物介绍:。主要内容为:"第一章苏乐醉酒后睡了个陌生男人,......决绝和坚定"。写作的字数大概为1000字。 写作额外要求(如果没写要求则没有额外要求):小说中人物介绍:。';

$preg = preg_replace('!{\d+}!', '([\s\S]+)', $str1);
$tp = preg_replace('!{\d+}!', '%s', $str1);

preg_match("!$preg!u", $str2, $matches);
$str3 = vsprintf($tp, array_map(static function ($item) {
    return '<span>' . $item . '</span>';
}, array_slice($matches, 1)));

var_dump($str3);
9个月前 评论
瀚海栏杆 (楼主) 9个月前

按照现在的模板文本来看,好像都是用户输入内容前的内容都是固定的?直接写死替换? :joy:

$str = '我现在想请你帮忙写一份{1}。主要内容为:"{2}"。写作的字数大概为{4}字。 写作额外要求(如果没写要求则没有额外要求):{3}';
        $str = str_replace("我现在想请你帮忙写一份","我现在想请你帮忙写一份<span>",$str);
        $str = str_replace("。主要内容为:","</span>。主要内容为:<span>",$str);
        $str = str_replace("。写作的字数大概为","</span>。写作的字数大概为<span>",$str);
        $str = str_replace("字。 写作额外要求(如果没写要求则没有额外要求):","</span>字。 写作额外要求(如果没写要求则没有额外要求):<span>",$str);
        $str .= "</span>";
9个月前 评论

你现在是有

$str1 = '我现在想请你帮忙写一份{1}。主要内容为:"{2}"。写作的字数大概为{4}字。 写作额外要求(如果没写要求则没有额外要求):{3}';

和这个

$str2 = ' 我现在想请你帮忙写一份小说中人物介绍:。主要内容为:"第一章苏乐醉酒后睡了个陌生男人,......决绝和坚定"。写作的字数大概为1000字。 写作额外要求(如果没写要求则没有额外要求。'

想替换成这个

$str3 = ' 我现在想请你帮忙写一份<span>小说中人物介绍:。</span>主要内容为:<span>"第一章苏乐醉酒后睡了个陌生男人,......决绝和坚定"</span>。写作的字数大概为<span>1000</span>字。 写作额外要求(如果没写要求则没有额外要求)'

是这种需求吗?

如果是的话,把 str1 改成正则,去 str2 里面匹配替换成 str3 就可以了

9个月前 评论
sanders

你要定义当出现重复内容时优先用哪段匹配,比如用户输入的内容为:

  1. 。主要内容为:"
  2. "。写作的字数大概为
  3. 字。 写作额外要求(如果没写要求则没有额外要求):
  4. 我现在想请你帮忙写一份

如果你无法控制用户输入的内容,被替换后的内容会出现重复,之后很难还原模板匹配的位置。

不考虑以上问题的可以试试:

$str = '我现在想请你帮忙写一份{1}。主要内容为:"{2}"。写作的字数大概为{4}字。 写作额外要求(如果没写要求则没有额外要求):{3}';
$target = '你现在是一位优秀的写作专家,在写作时会自主的选择和运用各种写作技巧、写作风格,或是引用名言名句。 我现在想请你帮忙写一份小说中人物介绍:。主要内容为:"第一章苏乐醉酒后睡了个陌生男人,......决绝和坚定"。写作的字数大概为1000字。 写作额外要求(如果没写要求则没有额外要求):小说中人物介绍:。';
$tpl = preg_replace('~\{\d+\}~', '(.*?)', $str);
$pattern = '~' . $tpl . '~m';
$inputs = [];
$matched = preg_match_all($pattern, $target, $inputs);
$source = array_map(fn($input) => $input[0], $inputs);
$replace = array_map(fn($input) => "<span class='bg-success'>{$input[0]}</span>", $inputs);
$result = str_replace($source, $replace, $target);
echo $result;
9个月前 评论

如果能提前确定格式,建议用占位符。

        $format = "现在想请你帮忙写一份%s。主要内容为:\"%s\"。写作的字数大概为%s字";
        $replace_strs = [
            '<span>小学生作文</span>','怎么样不写作文',99999
        ];
        dd(
            sprintf($format,... $replace_strs)
        );
9个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!