str_repeat反向(收缩字符串)

时间:2011-11-23 17:34:27

标签: php string

str_repeat(A,B)重复字符串 A B 次:

$string = "This is a " . str_repeat("test", 2) . 
          "! " . str_repeat("hello", 3) . " and Bye!";  

// Return "This is a testtest! hellohellohello and Bye!"

我需要反向操作:

str_shrink($string, array("hello", "test")); 
// Return "This is a test(x2)! hello(x3) and Bye!" or
//        "This is a [test]x2! [hello]x3 and Bye!"

创建 str_shrink 功能的最佳和有效方式?

5 个答案:

答案 0 :(得分:2)

以下是我可以提出的两个版本。

第一个使用正则表达式,并将$needle字符串的重复匹配替换为单个$needle字符串。这是经过最严格测试的版本,可以成功处理所有输入的可能性(据我所知)。

function str_shrink( $str, $needle)
{
    if( is_array( $needle))
    {
        foreach( $needle as $n)
        {
            $str = str_shrink( $str, $n);   
        }
        return $str;
    }
    $regex = '/(' . $needle . ')(?:' . $needle . ')+/i';
    return preg_replace_callback( $regex, function( $matches) { return $matches[1] . '(x' . substr_count( $matches[0], $matches[1]) . ')'; }, $str);
}

第二个使用字符串操作来不断替换与自身连接的$needle的出现。请注意,如果$needle.$needle在输入字符串中出现多次(第一个没有此问题),则此错误将会失败。

function str_shrink2( $str, $needle)
{
    if( is_array( $needle))
    {
        foreach( $needle as $n)
        {
            $str = str_shrink2( $str, $n);   
        }
        return $str;
    }
    $count = 1; $previous = -1;
    while( ($i = strpos( $str, $needle.$needle)) > 0)
    {
        $str = str_replace( $needle.$needle, $needle, $str);
        $count++;
        $previous = $i;
    }
    if( $count > 1)
    {
        $str = substr( $str, 0, $previous) . $needle .'(x' . $count . ')' . substr( $str, $previous + strlen( $needle));
    }
    return $str;
}

See them both in action

编辑:我没有意识到所需的输出想要包含重复次数。我相应地修改了我的例子。

答案 1 :(得分:1)

我想你可以试试:

<?php
$string = "This is a testtest! hellohellohello and Bye!";

function str_shrink($string, $array){
    $tr = array();
    foreach($array as $el){
        $n = substr_count($string, $el);
        $tr[$el] = $el.'(x'.$n.')';
        $pattern[] = '/('.$el.'\(x'.$n.'\))+/i';
    }
    return preg_replace($pattern, '${1}', strtr($string,$tr));
}

echo $string;
echo '<br/>';
echo str_shrink($string,array('test','hello'));  //This is a test(x2)! hello(x3) and Bye!
?>

我有第二个版本才能使用字符串:

<?php
$string = "This is a testtest! hellohellohello and Bye!";

function str_shrink($string, $array){
    $tr = array();
    $array = is_array($array) ? $array : array($array);
    foreach($array as $el){
        $sN = 'x'.substr_count($string, $el);
        $tr[$el] = $el.'('.$sN.')';
        $pattern[] = '/('.$el.'\('.$sN.'\))+/i';
    }
    return preg_replace($pattern, '${1}', strtr($string,$tr));
}

echo $string;
echo '<br/>';
echo str_shrink($string,array('test','hello'));  //This is a test(x2)! hello(x3) and Bye!
echo '<br/>';
echo str_shrink($string,'test');  //This is a test(x2)! hellohellohello and Bye!
?>

答案 2 :(得分:1)

你可以玩这个,但没有经过多少测试

function shrink($s, $parts, $mask = "%s(x%d)"){

            foreach($parts as $part){
                    $removed = 0;

                    $regex = "/($part)+/";

                    preg_match_all($regex, $s, $matches, PREG_OFFSET_CAPTURE);
                    if(!$matches)
                            continue;

                    foreach($matches[0] as $m){
                            $offset = $m[1] - $removed;
                            $nb = substr_count($m[0], $part);
                            $counter = sprintf($mask, $part, $nb);
                            $s = substr($s, 0, $offset) . $counter . substr($s, $offset + strlen($m[0]));
                            $removed += strlen($m[0]) - strlen($part);    
                    }

            }
            return $s;
    }

答案 3 :(得分:0)

我保持简短:

function str_shrink($haystack, $needles, $match_case = true) {
    if (!is_array($needles)) $needles = array($needles);
    foreach ($needles as $k => $v) $needles[$k] = preg_quote($v, '/');
    $regexp = '/(' . implode('|', $needles) . ')+/' . ($match_case ? '' : 'i');
    return preg_replace_callback($regexp, function($matches) {
        return $matches[1] . '(x' . (strlen($matches[0]) / strlen($matches[1])) . ')';
    }, $haystack);
}

str_shrink("aaa", array("a", "a(x3)"))这样的案例的行为是它返回"a(x3)",我认为如果您指定一个数组,则更有可能。对于其他行为,给出"a(x3)(x1)"的结果,请分别使用每个针调用该函数。

如果你不想要一个人的倍数来获得&#34;(x1)&#34;改变:

        return $matches[1] . '(x' . (strlen($matches[0]) / strlen($matches[1])) . ')';

为:

        $multiple = strlen($matches[0]) / strlen($matches[1]);
        return $matches[1] . (($multiple > 1) ? '(x' . $multiple . ')' : '');

答案 4 :(得分:0)

这是一种非常直接的单正则表达式技术,您无需事先收集字符串中的单词。

将减轻一些边缘情况,这些情况在示例输入中未表示,但是对于此任务的一般目的,我认为这是在项目中编写脚本的方式。

  1. 匹配(并捕获)重复一次或多次的完整单词。
  2. 匹配单词的连续重复。
  3. 用捕获的单词的第一个实例替换完整字符串匹配(多个单词的子字符串)。
  4. 在返回替换字符串以重新插入之前,添加所需的格式并通过将完整字符串的长度除以捕获的字符串的长度来计算重复次数。

代码:(Demo

$string = "This is a " . str_repeat("test", 2) . 
          "!\n" . str_repeat("hello", 3) . " and Bye!\n" .
          "When I sleep, the thought bubble says " . str_repeat("zz", 3) . ".";

echo preg_replace_callback(
         '~\b(\w+?)\1+\b~',
         function($m) {
             return "[{$m[1]}](" . (strlen($m[0]) / strlen($m[1])) . ")";
         },
         $string
     );

输出:

This is a [test](2)!
[hello](3) and Bye!
When I sleep, the thought bubble says [z](6).

对于针的白名单,对我上面的代码的这种修改几乎可以完成相同的工作。

代码:(Demo

function str_shrink($string, $needles) {
    // this escaping is unnecessary if only working with alphanumeric characters
    $needles = array_map(function($needle) {
        return preg_quote($needle, '~');
    }, $needles);

    return preg_replace_callback(
         '~\b(' . implode('|', $needles) . ')\1+\b~',
         function($m) {
             return "[{$m[1]}](" . (strlen($m[0]) / strlen($m[1])) . ")";
         },
         $string
     );
}

echo str_shrink($string, ['test', 'hello']);

输出:

This is a [test](2)!
[hello](3) and Bye!
When I sleep, the thought bubble says zzzzzz.