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 功能的最佳和有效方式?
答案 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;
}
编辑:我没有意识到所需的输出想要包含重复次数。我相应地修改了我的例子。
答案 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)
这是一种非常直接的单正则表达式技术,您无需事先收集字符串中的单词。
将减轻一些边缘情况,这些情况在示例输入中未表示,但是对于此任务的一般目的,我认为这是在项目中编写脚本的方式。
代码:(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.