PHP 初学者回文脚本

发布于 2024-11-24 16:19:37 字数 1178 浏览 4 评论 0原文

我正在(为了好玩)编写一个可以识别回文的脚本。到目前为止,我在“皮划艇”、“赛车”、“安娜”、“一个男人计划巴拿马运河”方面取得了成功:但后一个短语的变体,例如“amanaplana canalpan ama”给我带来了问题。

作为旁注:我确实知道使用 PCRE 会让事情对我来说更容易,但我对此并不流利,我的主要目标之一是了解检查回文背后的算法。

 <?php
$word = "amanaplana canalpan ama";

$space = " ";
$word_smallcase = strtolower($word);        

$word_array = str_split($word_smallcase);   

if(in_array($space, $word_array)){      

    for($m = 0; $m<count($word_array); $m = $m + 1){
        if($word_array[$m] == $space)
            unset($word_array[$m]);
    }
}
$count = 0;
$scan_count = -1;
for($i = 0; $i < (count($word_array)/2); $i = $i + 1){

    for($j = count($word_array); $j > (count($word_array)/2); $j = $j - 1){

        if($word_array[$i]==$word_array[$j]){
            $count = $count + 1;
            break;
            }
        }
    $scan_count = $scan_count + 1;

        }
if ($count == $scan_count){
    echo $word." is a palindrome";
}
else{

    echo $word ." is NOT a palindrome";
}


?>

我希望得到有关以下问题的答复:

  • 我遇到的错误的识别。
  • 关于以下方面的建议 我如何才能改进代码(如果我能做的话我会很高兴 事情无需诉诸 $count 或 $scan_count 即可工作,这似乎是 我的眼睛,相对业余)。

提前致谢。

I was working on (for fun) writing a script that would recognize palindromes. So far, I'm successful with "Kayak", "Racecar", "Anna", "A man a plan a canal Panama": yet variations on the latter phrase such as "amanaplana canalpan ama" gives me problems.

As a side note: I do understand that using PCRE would make things a lot easier for me, but I'm not fluent in it and one of my major aims was to understand the algorithm behind checking for palindromes.

 <?php
$word = "amanaplana canalpan ama";

$space = " ";
$word_smallcase = strtolower($word);        

$word_array = str_split($word_smallcase);   

if(in_array($space, $word_array)){      

    for($m = 0; $m<count($word_array); $m = $m + 1){
        if($word_array[$m] == $space)
            unset($word_array[$m]);
    }
}
$count = 0;
$scan_count = -1;
for($i = 0; $i < (count($word_array)/2); $i = $i + 1){

    for($j = count($word_array); $j > (count($word_array)/2); $j = $j - 1){

        if($word_array[$i]==$word_array[$j]){
            $count = $count + 1;
            break;
            }
        }
    $scan_count = $scan_count + 1;

        }
if ($count == $scan_count){
    echo $word." is a palindrome";
}
else{

    echo $word ." is NOT a palindrome";
}


?>

I'd appreciate a response regarding:

  • The identification of the bug I'm having.
  • Recommendations as to
    how I could possibly improve the code (I'd be happy if I could make
    things work without resorting to $count or $scan_count which seem, to
    my eye, relatively amateurish).

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风轻花落早 2024-12-01 16:19:37

目前,您正在逐字进行测试,如果回文中单词不均匀,这肯定会导致错误。

在 PHP 中查看字符串是否是回文的简单方法:

$test = str_replace( array(',', '.', ' '
                     //, and any other punctuation you aren't using
                     ), '', $input );

$test = strtolower( $test );
echo $input . ' is ' . 
             ( ( strrev( $test ) == $test )? "": "not " )
             ' palandromic.';

至于您的代码:迭代数组并同时删除内容会带来麻烦。你最好只使用 str_replace 。如果这不是一个选项,我会使用:

// this takes more space, but it is easier to understand.
$tmp = array();
for($m = 0; $m<count($word_array); $m++){ // ++ is the same as $m = $m + 1
    if($word_array[$m] != $space)
        $tmp[] = $word_array[$m];
}
$word_array = $tmp;

如果 strrev (反转字符串)不可用:

$l = count( $word_array ) / 2; // cache this, no sense in recounting
$is_palindromic = TRUE;
for( $i = 0; $i < $l; $i++ )
{
    if( $word_array[ $i ] != $word_array[ ( -1 - $i ) ] )
    {
        $is_palindromic = FALSE;
        break;
    }
}

echo $input . ' is ' . 
         ( $is_palindromic )? "": "not " )
         ' palandromic.';

Currently, you're testing on a word-for-word basis, and that will definitely cause bugs in cases where words are uneven across the palindrome.

The easy way to see if a string is palandromic in PHP:

$test = str_replace( array(',', '.', ' '
                     //, and any other punctuation you aren't using
                     ), '', $input );

$test = strtolower( $test );
echo $input . ' is ' . 
             ( ( strrev( $test ) == $test )? "": "not " )
             ' palandromic.';

As to your code: iterating through an array and removing things at the same time is an invitation to trouble. You're better just using str_replace. If that isn't an option, I would use:

// this takes more space, but it is easier to understand.
$tmp = array();
for($m = 0; $m<count($word_array); $m++){ // ++ is the same as $m = $m + 1
    if($word_array[$m] != $space)
        $tmp[] = $word_array[$m];
}
$word_array = $tmp;

If strrev (reverses a string) is not available:

$l = count( $word_array ) / 2; // cache this, no sense in recounting
$is_palindromic = TRUE;
for( $i = 0; $i < $l; $i++ )
{
    if( $word_array[ $i ] != $word_array[ ( -1 - $i ) ] )
    {
        $is_palindromic = FALSE;
        break;
    }
}

echo $input . ' is ' . 
         ( $is_palindromic )? "": "not " )
         ' palandromic.';
迷离° 2024-12-01 16:19:37

这里发生了一些事情......

首先,我不确定您是否意识到unset'ing数组实际上并没有删除索引:

$array = array(0, 1, 2, 3);
unset($array[2]);
var_dump($array);
/* array(3) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [3]=>
  int(3)
} */

所以您将会有当您迭代数组中的元素时,会出现一些未定义的偏移量。要一一进行,您应该使用 foreach 循环控制。

另一个问题在于这里的嵌套 for 循环:

for($i = 0; $i < (count($word_array)/2); $i = $i + 1){

    for($j = count($word_array); $j > (count($word_array)/2); $j = $j - 1){

给定“amanaplanacanalpanama”,看看你在做什么:

一步一步进行比较(顺便说一句,你在 $j... $ 的初始化器上偏离了 1 word_array[count($word_array)] 指向巴拿马的“m”,而不是“a”。):

a eq to a?              j is 22          i is 0
                scan_count: -1   count: 1
m eq to a?              j is 22          i is 1
m eq to m?              j is 21          i is 1
                scan_count: 0    count: 2
a eq to a?              j is 22          i is 2
                scan_count: 1    count: 3

a eq to a 很好,并且匹配... m被发现于下一次迭代,但是当你到达下一个“a”时,你会在巴拿马的末尾找到原始的“a”...

顺便说一句,因为你每次都从最后开始,所以给定足够大的字符串,效率会非常低O(n^2)...

强制解决方案:

$word = "amanaplana canalpan ama";

$j = strlen ($word)-1;
$pal = true;

for ($i = 0; $i < strlen($word)/2; ++$i, --$j) {

    // skip spaces
    while ($word[$i] === " ") {$i++;}
    while ($word[$j] === " ") {$j--;}

    echo "$word[$i] eq $word[$j]?\n";
    if ($word[$i] !== $word[$j])    {
        $pal = false;
        break;
        }
}

if ($pal) print "yes"; else print "no";

There's a few things going on here...

First, I'm not sure if you're aware that unset'ing the array doesn't actually remove the indices:

$array = array(0, 1, 2, 3);
unset($array[2]);
var_dump($array);
/* array(3) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [3]=>
  int(3)
} */

So you're going to have some undefined offsets when you iterate over the elements in the array. To go one by one, you should use the foreach loop control.

Another issue lies in the nested for loop here:

for($i = 0; $i < (count($word_array)/2); $i = $i + 1){

    for($j = count($word_array); $j > (count($word_array)/2); $j = $j - 1){

Given "amanaplanacanalpanama", look at what you're doing:

comparing, step by step (btw, you're off by 1 on the initializer for $j... $word_array[count($word_array)] is pointing at the 'm' in panama, not the 'a'.):

a eq to a?              j is 22          i is 0
                scan_count: -1   count: 1
m eq to a?              j is 22          i is 1
m eq to m?              j is 21          i is 1
                scan_count: 0    count: 2
a eq to a?              j is 22          i is 2
                scan_count: 1    count: 3

a eq to a is fine, and matches... m is found on the next iteration, but when you get to the next 'a', you're finding the original 'a' at the end of panama...

As a side note, since you are starting over from the very end every time, it would be horribly inefficient O(n^2) given a sufficiently large string...

Obligatory solution:

$word = "amanaplana canalpan ama";

$j = strlen ($word)-1;
$pal = true;

for ($i = 0; $i < strlen($word)/2; ++$i, --$j) {

    // skip spaces
    while ($word[$i] === " ") {$i++;}
    while ($word[$j] === " ") {$j--;}

    echo "$word[$i] eq $word[$j]?\n";
    if ($word[$i] !== $word[$j])    {
        $pal = false;
        break;
        }
}

if ($pal) print "yes"; else print "no";
甩你一脸翔 2024-12-01 16:19:37

伪代码:

string phrase = "my phrase here"

int i = 0
int j = phrase.length - 1

while i < j:
  if phrase[i] is not alphanumeric:
    i++;
    continue;
  if phrase[j] is not alphanumeric:
    j--;
    continue;
  if phrase[i] != phrase[j]
    return false;
  i++;
  j--;

return true

pseudocode:

string phrase = "my phrase here"

int i = 0
int j = phrase.length - 1

while i < j:
  if phrase[i] is not alphanumeric:
    i++;
    continue;
  if phrase[j] is not alphanumeric:
    j--;
    continue;
  if phrase[i] != phrase[j]
    return false;
  i++;
  j--;

return true
木落 2024-12-01 16:19:37

认为可以删除所有空格并完全忽略单词。只需将其分成两部分(如果字符串长度为奇数,则将其分成两部分),反转任意一半,然后查看它们是否匹配。

$word = "amanaplana canalpan ama";

$sanitizedWord = preg_replace("'\s+'", '', strtolower($word));
$halfway = strlen($sanitizedWord)/2;
$roundedDownMidPoint = floor($halfway);

$firstHalf = substr($sanitizedWord, 0, $roundedDownMidPoint);
$secondHalf = substr($sanitizedWord, is_float($halfway) ? $roundedDownMidPoint+1 : $halfway);

if ($firstHalf === strrev($secondHalf)) {
    echo $sanitizedWord." is a palindrome";
}

使用“Kayak”、“Racecar”、“Anna”、“A man a plan a canal Panan”和“amanaplana canalpan ama”进行测试,这些都被正确识别为回文。

I think it is possible to just remove all the spaces and ignore words completely. Just split into two (or thereabouts if string length is an odd number), reverse any half and then see if they match.

$word = "amanaplana canalpan ama";

$sanitizedWord = preg_replace("'\s+'", '', strtolower($word));
$halfway = strlen($sanitizedWord)/2;
$roundedDownMidPoint = floor($halfway);

$firstHalf = substr($sanitizedWord, 0, $roundedDownMidPoint);
$secondHalf = substr($sanitizedWord, is_float($halfway) ? $roundedDownMidPoint+1 : $halfway);

if ($firstHalf === strrev($secondHalf)) {
    echo $sanitizedWord." is a palindrome";
}

Tested with "Kayak", "Racecar", "Anna", "A man a plan a canal Panama" and "amanaplana canalpan ama" which are all identified correctly as palindromes.

记忆消瘦 2024-12-01 16:19:37
<?php
$a="amanaplana canalpan ama";
echo "String entered: " . $a;
$b= preg_replace('/\s+/', '', $a);
$org= strtolower($b);
$chk= strrev($org);
echo "<br/>";
if ($org==$chk)
{ echo "Palindrome"; }
else
{ echo "Not Palindrome"; }
?>
<?php
$a="amanaplana canalpan ama";
echo "String entered: " . $a;
$b= preg_replace('/\s+/', '', $a);
$org= strtolower($b);
$chk= strrev($org);
echo "<br/>";
if ($org==$chk)
{ echo "Palindrome"; }
else
{ echo "Not Palindrome"; }
?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文