【问题标题】:Implement ROT13 with PHP用 PHP 实现 ROT13
【发布时间】:2012-05-04 17:08:00
【问题描述】:

我在阅读了有关 Jon Skeet 的有趣内容后发现了一个字符串,我猜它在 ROT13 中。在检查我的猜测之前,我想我会尝试用 PHP 解密它。这是我所拥有的:

$string = "Vs lbh nfxrq Oehpr Fpuarvre gb qrpelcg guvf, ur'q pehfu lbhe fxhyy jvgu uvf ynhtu.";
$tokens = str_split($string);
for ($i = 1; $i <= sizeof($tokens); $i++) {
    $char = $tokens[$i-1];
    for ($c = 1; $c <= 13; $c++) {
        $char++;
    }
    echo $char;
}

我的字符串返回为AIaf you aasakaead ABruacae Sacahnaeaiaer to adaeacrypt tahais, ahae'ad acrusah your sakualal waitah ahais alaauagah.

我的逻辑似乎很接近,但显然是错误的。你能帮我吗?

【问题讨论】:

  • 对于它的价值(对于将其标记为加密的人),rot13 不是加密,它是一个密码。加密涉及一个密钥,使用该密钥会使相关数据变得不可读,以使在没有加密密钥的情况下难以获得数据。
  • @damianb 好吧,这是 ROT 加密,密钥值为 13 :)。我可以理解encryption 标签,它吸引了合适的人群,可能人们会使用这个词来寻找问题/解决方案,它在这方面确实有效。

标签: php encryption rot13


【解决方案1】:

试试str_rot13

http://us.php.net/manual/en/function.str-rot13.php

无需自己制作,它是内置的。

【讨论】:

  • 啊,谢谢。我不知道那件事。尽管如此,重点是锻炼我的大脑,所以我仍然想自己构建它。
【解决方案2】:

这是一个有效的实现,没有使用嵌套循环。您也不需要将字符串拆分为数组,因为您可以像 PHP 中的字符串数组一样对单个字符进行索引。

您需要知道 ASCII 大写字符的范围是 65 - 99,小写字符的范围是 97 - 122。如果当前字符在其中一个范围内,则将 13 添加到其 ASCII 值。然后,您检查是否应该滚动到字母表的开头。如果您应该翻车,请减去 26。

$string = "Vs lbh nfxrq Oehpr Fpuarvre gb qrpelcg guvf, ur'q pehfu lbhe fxhyy jvgu uvf ynhtu.";

for ($i = 0, $j = strlen( $string); $i < $j; $i++) 
{
    // Get the ASCII character for the current character
    $char = ord( $string[$i]); 

    // If that character is in the range A-Z or a-z, add 13 to its ASCII value
    if( ($char >= 65  && $char <= 90) || ($char >= 97 && $char <= 122)) 
    {
        $char += 13; 

        // If we should have wrapped around the alphabet, subtract 26
        if( $char > 122 || ( $char > 90 && ord( $string[$i]) <= 90)) 
        {
            $char -= 26;
        }
    }
    echo chr( $char);
}

这会产生:

如果你让布鲁斯·施奈尔解密这个,他会用他的笑来粉碎你的头骨。

【讨论】:

    【解决方案3】:

    如果您想自己执行此操作,而不是使用现有的解决方案,您需要检查每个字母是在字母表的前半部分还是后半部分。您不能天真地为每个字符添加 13(另外,为什么要使用循环添加 13?!)。您必须将 13 加到 A-M 并从 N-Z 中减去 13。您还不得更改任何其他字符,例如空格。

    更改代码以在更改之前检查每个字符的内容,以便了解是否以及如何更改它。

    【讨论】:

      【解决方案4】:

      这不起作用,因为 z++ 是 aa

      $letter = "z";
      $letter++;
      echo($letter);
      

      返回 aa 而不是 a

      编辑:不使用内置的可能替代解决方案是

      $string = "Vs lbh nfxrq Oehpr Fpuarvre gb qrpelcg guvf, ur'q pehfu lbhe fxhyy jvgu uvf ynhtu.";
      $tokens = str_split($string);
      
      foreach($tokens as $char)
      {
          $ord = ord($char);
          if (($ord >=65 && $ord <=90 ) || ($ord >= 97 && $ord <= 122))
          $ord = $ord+13;
          if (($ord > 90 && $ord < 110) || $ord > 122)
              $ord = $ord - 26;
          echo (chr($ord));
      }
      

      【讨论】:

        【解决方案5】:

        聚会晚了几年,但我想我会给你另一个选择

        function rot13($string) {
            // split into array of ASCII values
            $string = array_map('ord', str_split($string));
        
            foreach ($string as $index => $char) {
                if (ctype_lower($char)) {
                    // for lowercase subtract 97 to get character pos in alphabet
                    $dec = ord('a');
                } elseif (ctype_upper($char)) {
                    // for uppercase subtract 65 to get character pos in alphabet
                    $dec = ord('A');
                } else {
                    // preserve non-alphabetic chars
                    $string[$index] = $char;
                    continue;
                }
                // add 13 (mod 26) to the character
                $string[$index] = (($char - $dec + 13) % 26) + $dec;
            }
        
            // convert back to characters and glue back together
            return implode(array_map('chr', $string));
        }
        

        【讨论】: