Php 递归函数

Php 递归函数,php,Php,我完全不知道,所以如果有人能给我指出正确的方向,我将不胜感激 我想要像这样的东西 <?php function square($num) { // something } name('{3}'); // have this return 9 name('{6}'); // have this return 36 name('{{{2}}}'); // have this return 256 name('{9}{12}'); // have this return 81144 name(

我完全不知道,所以如果有人能给我指出正确的方向,我将不胜感激

我想要像这样的东西

<?php
function square($num) {
// something
}

name('{3}'); // have this return 9
name('{6}'); // have this return 36
name('{{{2}}}'); // have this return 256
name('{9}{12}'); // have this return 81144
name('{{5}}'); // have this return 125
name('adscdc{4}{{3}}'); // have this return adscdc1681
?>

有人知道怎么做吗?提前感谢:) 到目前为止,我已经:

<?php
function square($text) {
    $parts = explode('{', $text);
    foreach($parts as $part) {
        $piece = explode('}', $part);
        $text = str_replace('{' . $piece[0] . '}', pow($piece[0], 2), $text);
    }
    return $text;
}
echo square('aasd{3}');
?>


这得到了{}方括号,对于每个方括号都得到了小数点,并对嵌套的方括号数进行了幂运算,输出被浓缩到字符串中,而不是解析的方括号中,没有任何分隔符。

您可能需要解析字符串。继续阅读字符,直到到达一个大括号,然后在每个大括号上增加一个计数器。当你得到一个数字时,把它提高到计数器的倍数。然后为每个右大括号递减,如果大括号不匹配,则抛出异常。

这不一定是递归函数。除了其他提到的核心逻辑之外,您还需要确保输入字符串是否有效。例如:

name('{{9}{{{{{1}');
name('{abbc}');
name('{}');

看起来很简单。当你发现一个动机时,比如在花括号内的数字,它应该被数字的平方所取代。如果没有更换,则完成更换。如果你在哪里做了一些替换,你可以再做一次(因为刚才被替换的东西现在可能在花括号内)等等

第一部分(替换)可以使用regex完成,第二部分可以递归或迭代完成

下面是一些可以帮助您理解细节的代码片段(不是完整答案,但不远)。练习的目的似乎是帮助您理解
preg\u replace()
参数

<?php
$count = 0;
echo preg_replace('/[{](\d+)[}]/e', '$1*$1', '{{{2}}}', -1, $count);
echo "\n";
echo "$count replacement done\n";
?>
对于好奇的读者,正如其他人建议的python版本,下面是一个可能的perl等价物:

#!/usr/bin/perl

my @tests = ('{3}','{6}','{{{2}}}','{9}{12}','{{5}}', 'adscdc{4}{{3}}'); 

sub square {
    my $str = pop;
    while ($str =~ s/[{](\d+)[}]/$1*$1/e) {};
    return $str;
}

for my $str (@tests){
    print "$str --> ".square($str)."\n" ;
} 
Perl中有安全机制来避免注入,因为恶意用户输入不同于盲目拒绝所有eval。对于那些感兴趣的人,你可以看看

和其他两个较短的python版本,递归:

import re
test = ['5','{3}','{6}','{{{2}}}','{9}{12}','adscdc{4}{{3}}']

def square(txt):
   txt2 = re.sub('{(\d+)}',lambda m: str(int(m.group(1)) ** 2) , txt)
   if txt2 == txt:
        return txt
   return square(txt2)

for x in test:
    print("%s --> %s" % (x, square(x)))
和非递归

import re
test = ['5','{3}','{6}','{{{2}}}','{9}{12}','adscdc{4}{{3}}']

def square(txt):
    oldtxt = None
    while oldtxt != txt:
        oldtxt = txt
        txt = re.sub('{(\d+)}',lambda m: str(int(m.group(1)) ** 2) , oldtxt)
    return txt

for x in test:
    print("%s --> %s" % (x, square(x)))

我认为{{5}}应该是625,对吗

无论如何,请尝试以下方法:

<?php

  function name ($str) { 
    while (1) {
      preg_match('/{(\d+)}/', $str, $matches);
      if (count($matches)<2) return $str;
      $str=str_replace($matches[0], $matches[1]*$matches[1], $str);
    }
  }

  echo "\n<pre>\n".
       name('{3}'). // have this return 9
       "\n".
       name('{6}'). // have this return 36
       "\n".
       name('{{{2}}}'). // have this return 256
       "\n".
       name('{9}{12}'). // have this return 81144
       "\n".
       name('{{5}}'). // have this return 625
       "\n".
       name('adscdc{4}{{3}}'). // have this return adscdc1681
       "\n</pre>\n";

?>

…跑步给了我这些结果:

>>> import re
>>> test = [('5','5'),('{3}','9'),('{6}','36'),('{{{2}}}','256'),('{9}{12}','81144'),('adscdc{4}{{3}}','adscdc1681')]
>>> def eval(txt):
...   replace = lambda t: re.sub('{(\d+)}',lambda match: str(int(match.group(1)) * int(match.group(1))),t)
...   while(re.search('[{}]',txt) != None):
...     txt = replace(txt)
...   return txt
... 
>>> for t in test:
...   print (t[0],t[1],eval(t[0]) == t[1])
... 
('5', '5', True)
('{3}', '9', True)
('{6}', '36', True)
('{{{2}}}', '256', True)
('{9}{12}', '81144', True)
('adscdc{4}{{3}}', 'adscdc1681', True)
9 36 256 81144 625 adscdc1681
我觉得这个问题很有趣。但是我已经在PHP中看到了一些很好的答案,所以为了训练自己,我用Python实现了一个解决方案。如果您感兴趣,可以在此处查看:

同样有趣的是,python虽然是许多解决方案的一种非常强大的语言,但在处理正则表达式时通常会生成非常难看的代码


(这篇文章并不是为了回答所贴的问题,因为已经有足够多的好答案了。我只是把它分享给感兴趣的人。)

这看起来像是家庭作业。到目前为止你有什么?这不应该是递归的。这是要求吗?这不是家庭作业。我已经设法得到了{3},但没有得到{3}。也许是使用str_split,然后foreach解析它们?@Tech163只是迭代字符串的字符。@TokenMacGuy-这是一个完美的例子,说明使用regex很痛苦,没有regex很简单。@TokenMacGuy:你应该看看我的答案,然后重新考虑。如果你知道正确的选项,那么使用正则表达式几乎是一个愚蠢的单行程序?这意味着逐位解析字符串并动态计算数字,或者至少将数字的所有数字存储在字符串中。当然可以这样做,但既然正则表达式几乎可以做所有必要的事情,为什么还要重新发明轮子呢?另外,在问题中,哪里说禁止使用不匹配的大括号?这个问题并没有给我们任何提示。大括号匹配是由我所描述的算法处理的——打开时递增,关闭时递减,并检查它是否在新的递增之前回到零。不过,关于检查大括号中的非数字字符之类的内容,您是对的。我认为在输入中包含非数字字符是有点愚蠢的要求。它也由正则表达式解决方案处理。字符串始终有效,不匹配的大括号将变为文字字符。如果要进行严格检查,请检查结果字符串,如果它包含任何
{
}
字符,则引发异常。@stereofrog:没错,分组只是一种可读性习惯(Damien Conway在《Perl最佳实践》中提出的建议,我对此很感兴趣。)
/e
修饰符(
PREG\u REPLACE\u EVAL
)这就是问题所在。它被视为一种安全风险,因为它的工作方式类似于
eval
。像Suhosin这样的mod禁用
/e
,所以它不会在任何地方都起作用…@否:是的,但由于这个问题没有标记为硬化php或Suhosin,我相信你的评论与此无关。而且/e的这种特殊用法在这里也不是一个安全问题。至少你知道uld在回答中解释为什么您不选择直接路径,而是选择一些解决方法(而不是直接路径:使用preg_replace_callback而不是/e)如果可能的话,
/e
修饰符,如使用
eval
,通常是人们应该避免的,特别是如果解决方法需要一行额外的代码。我认为通常不需要解释为什么像
eval
这样的事情是最好避免的。@no:看起来像是重复的,但无法解释n、 如果它最初是以多种语言引入的,那是有原因的(有些事情没有eval是很难做到的).但在这里,最让我困扰的是进行两次代价高昂的字符串搜索,而不是一次调用preg_match,然后调用preg_replace,以避免preg_replace,据说是为了避免调用eval。这也使代码维护难度增加了两倍,调试难度增加了两倍。没问题:)我考虑了一下,对它进行了编辑,这样函数就可以返回值,而不是回显它们。。。现在我觉得它更简单了一点。如果你不喜欢
while(1)
----的话,你也可以把它变成
do
while
循环
<?php

  function name ($str) { 
    while (1) {
      preg_match('/{(\d+)}/', $str, $matches);
      if (count($matches)<2) return $str;
      $str=str_replace($matches[0], $matches[1]*$matches[1], $str);
    }
  }

  echo "\n<pre>\n".
       name('{3}'). // have this return 9
       "\n".
       name('{6}'). // have this return 36
       "\n".
       name('{{{2}}}'). // have this return 256
       "\n".
       name('{9}{12}'). // have this return 81144
       "\n".
       name('{{5}}'). // have this return 625
       "\n".
       name('adscdc{4}{{3}}'). // have this return adscdc1681
       "\n</pre>\n";

?>
9 36 256 81144 625 adscdc1681
>>> import re
>>> test = [('5','5'),('{3}','9'),('{6}','36'),('{{{2}}}','256'),('{9}{12}','81144'),('adscdc{4}{{3}}','adscdc1681')]
>>> def eval(txt):
...   replace = lambda t: re.sub('{(\d+)}',lambda match: str(int(match.group(1)) * int(match.group(1))),t)
...   while(re.search('[{}]',txt) != None):
...     txt = replace(txt)
...   return txt
... 
>>> for t in test:
...   print (t[0],t[1],eval(t[0]) == t[1])
... 
('5', '5', True)
('{3}', '9', True)
('{6}', '36', True)
('{{{2}}}', '256', True)
('{9}{12}', '81144', True)
('adscdc{4}{{3}}', 'adscdc1681', True)