【问题标题】:Replacing matching strings from array keys in a string从字符串中的数组键替换匹配的字符串
【发布时间】:2020-01-22 04:29:33
【问题描述】:

我的目标是,在一个字符串中,找到一个假定数组的键,并在该字符串中,用数组中匹配的键替换这些键。

我有一个小而有用的函数,可以在 2 个分隔符之间找到我的所有字符串(沙盒链接:https://repl.it/repls/UnlinedDodgerblueAbstractions):

function findBetween( $string, $start, $end )
{
    $start = preg_quote( $start, '/' );
    $end = preg_quote( $end, '/' );

    $format = '/(%s)(.*?)(%s)/';

    $pattern = sprintf( $format, $start, $end );

    preg_match_all( $pattern, $string, $matches );

    $number_of_matches = is_string( $matches[2] ) ? 1 : count( $matches[2] );

    if( $number_of_matches === 1 ) {
        return $matches[2];
    }

    if( $number_of_matches < 2 || empty( $matches ) ) {
        return False;
    }

    return $matches[2];
}

例子:

findBetween( 'This thing should output _$this_key$_ and also _$this_one$_ so that I can match it with an array!', '_$', '$_')

应该返回一个包含值['this_key', 'this_one'] 的数组。问题是,我怎样才能将它们替换为关联数组的值?

假设我的数组是这样的:

[
    'this_key' => 'love',
    'this_one' => 'more love'
];

我的输出应该是这样的:

This thing should output love and also more love so that I can match it with an array!

我怎样才能做到这一点?

【问题讨论】:

    标签: php regex preg-replace preg-match


    【解决方案1】:

    使用strtr 可能比使用正则表达式更容易解决这个问题。我们可以使用array_map$replacements的key周围加上$start$end的值,然后使用strtr进行替换:

    $str = 'This thing should output _$this_key$_ and also _$this_one$_ so that I can match it with an array!';
    $replacements = [
        'this_key' => 'love',
        'this_one' => 'more love'
    ];
    $start = '_$';
    $end = '$_';
    $replacements = array_combine(array_map(function ($v) use ($start, $end) { return "$start$v$end"; }, array_keys($replacements)), $replacements);
    echo strtr($str, $replacements);
    

    输出:

    This thing should output love and also more love so that I can match it with an array!
    

    Demo on 3v4l.org

    如果因为每次都必须重新生成 $replacements 数组而导致性能问题,那么这个循环会快得多:

    foreach ($replacements as $key => $value) {
        $new_reps["_\$$key\$_"] = $value;
    }
    

    性能对比demo on 3v4l.org

    【讨论】:

    • 哟!这是要走的路。你能解释一下这里发生了什么吗?
    • @DanielM 看一下strtr 的手册,它有一个可以替换数组的形式。我所做的是使用array_map 将替换数组转换为看起来像[ '_$this_key$_' =&gt; 'love', '_$this_one$_' =&gt; 'more love' ],然后strtr 遍历字符串,按照该数组中的描述进行替换。
    • 感谢您的解释,我可以看到它在做什么,但我已经测试过,@Julio 的回答是快得多。
    • @DanielM 这让我很惊讶。我希望strtr 比任何形式的preg_replace 都快得多,尤其是每次匹配都会产生函数调用的开销。
    • 同时,这个函数会解析数组 3 次,每次更高级别的解析会变得更难,因为较低级别的项目越多,而 preg_replace 仅在内部执行循环 afaik。
    【解决方案2】:

    您可以使用preg_replace_callback:

    <?php
    
    $str = 'This thing should output _$this_key$_ and also _$this_one$_ so that I can match it with an array!';
    
    $replacements = [
        'this_key' => 'love',
        'this_one' => 'more love'
    ];
    
    $replaced = preg_replace_callback('/_\$([^$]+)\$_/', function($matches) use ($replacements) {
        return $replacements[$matches[1]];
    }, $str);
    
    print $replaced;
    

    你有一个演示 here

    正则表达式,解释:

    _              # Literal '_'
    \$             # Literal '$' ($ needs to be scaped as it means end of line/string)
    (              # Begin of first capturing group
        [^$]+      # One carcter that cannot be "$", repeated 1 or more times
    )              # End of first capturing group
    \$             # Literal '$'
    _              # Literal '_'
    

    对于每个匹配,匹配的数据 ($mathces) 被传递给函数。

    在数组的第一个元素上有第一个捕获组,我们用它来进行替换。

    【讨论】:

    • 嘿胡里奥!你能告诉我这与@Nick 的答案相比如何?
    • 我实际上只是继续测试了这个。你的比尼克的快得多。我正试图找出原因。
    • 它们都有效!我只是使用不同的方法提出了另一种选择 :) 但要注意基准测试,除非您使用大量数据,否则基准测试可能毫无用处。此外,除非性能至关重要,否则我只会使用更易于阅读/维护的解决方案。
    【解决方案3】:

    希望这能解决您的问题!

    $items['this_key'] = 'love';
    $items['this_one'] = 'more love';
    
    $string = 'This thing should output _$this_key$_ and also _$this_one$_ so that I can match it with an array!';
    
    $this_key = $items['this_key'];
    $this_one = $items['this_one'];
    $string = str_replace('_$this_key$_',$this_key,$string);
    $string = str_replace('_$this_one$_',$this_one,$string);
    
    echo  $string;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多