Javascript 中的凯撒密码

Caesar Cipher in Javascript

我正在尝试编写一个程序来解决javascript中的以下问题(写在本段下方)。我不知道为什么我的代码不起作用。有人可以帮我吗?我是 javascript 的新手;这是一个免费的代码训练营问题。

“一种常见的现代用法是 ROT13 密码,其中字母的值移动 13 个位置。因此 'A' ↔ 'N'、'B' ↔ 'O' 等等。

编写一个函数,将 ROT13 编码字符串作为输入,returns 解码字符串。

function rot13(str) { // LBH QVQ VG!
  
  var string = "";
  for(var i = 0; i < str.length; i++) {
    var temp = str.charAt(i);
    if(temp !== " " || temp!== "!" || temp!== "?") {
       string += String.fromCharCode(13 + String.prototype.charCodeAt(temp));
    } else {
      string += temp;
    }
  }
  
  return string;
}

// Change the inputs below to test
console.log(rot13("SERR PBQR PNZC")); //should decode to "FREE CODE CAMP"

虽然 A + 13 可能等于 N,但 Z + 13 将无法正确计算。

您可以直接为 ROT13 构建算法...或者只使用具有适当密钥的凯撒密码算法。

我为您的示例提出的替代方案只是常规凯撒密码算法的一种特殊用法 – 一种非常简单的加密形式,其中原始消息中的每个字母都向左或向右移动一定数量的职位。

要解密消息,我们只需将字母向后移动相同数量的位置。

示例:

    如果我们将所有字母移动 3 个位置,
  • JAVASCRIPT 变为 MDYDVFULSW
  • 如果我们将所有字母向后移动 3 个位置,MDYDVFULSW 将返回 JAVASCRIPT。

如果一个字母在移位后超出了字母范围,则该字母在字母表中环绕。示例:如果字母 Z 移动 3 个位置,则变为 C。

这种“环绕”效果意味着使用 modulo。用数学术语来说,以上可以表示为:

En(x) = (x + n) mod 26

Dn(x) = (x – n) mod 26

如果不使用适当的 modulo 运算符而尝试在 JavaScript 中实施此算法,将会产生不正确的结果或非常神秘且难以理解的代码。

最大的问题是 JavaScript 不包含 modulo 运算符。 % 运算符只是除法的提醒 - 而不是 modulo。但是,将 modulo 实现为自定义函数非常容易:

// Implement modulo by replacing the negative operand 
// with an equivalent positive operand that has the same wrap-around effect
function mod(n, p)
{
    if ( n < 0 )
        n = p - Math.abs(n) % p;

    return n % p;
}

还有其他实现方法modulo...如果您有兴趣可以参考这个article

通过使用上面定义的mod函数,代码以相同的方式表达数学等式:

// Function will implement Caesar Cipher to
// encrypt / decrypt the msg by shifting the letters
// of the message acording to the key
function encrypt(msg, key)
{
    var encMsg = "";

    for(var i = 0; i < msg.length; i++)
    {
        var code = msg.charCodeAt(i);

        // Encrypt only letters in 'A' ... 'Z' interval
        if (code >= 65 && code <= 65 + 26 - 1)
        {
            code -= 65;
            code = mod(code + key, 26);
            code += 65;
        }

        encMsg += String.fromCharCode(code);
    }

    return encMsg;
}

要使用 ROT13 编码...现在只需按照算法名称选择合适的密钥即可。

const rot13 = (string) => {
//  creating *letterBox* - string in alphabetic way
  const letterBox = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// declaring *iter function* - that will pass through the text 
  const iter = (str, acc) => {   
// if length of string is 0 (phrase is empty) => returning *accumulator*
      if (str.length===0) { return acc; }
/* if is not an uppercase character => calling *function iter* by itself 
with the new string minus first letter and adding to *accumulator*
without coding symbol */ 
      if (! /^[A-Z]*$/.test(str[0])) {return iter(str.substring(1), acc+str[0]); };
// and now we loop through the uppercase letters (26 letters)
//checking their index in our *letterBox*
// if it's more that 13 , we add 13 , else we substract 13 and   
// and of course... calling *iter function* with new string minus first character 
// plus *accumumator* 
     for (let i=0; i<26;i++)
     {
       if ( (letterBox[i]===str[0]) && (i>12))
       { return iter(str.substring(1), acc + letterBox[i-13]); }
       if ( (letterBox[i]===str[0])&& (i<13))
       { return  iter(str.substring(1), acc + letterBox[i+13]); };
      };
  };
 // calling *iter function* with the provided *string* and empty *accumulator*    
 return iter(string,'');
};
   console.log(rot13('GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.'));
// THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.

通过了 codecamp 的成功测试。 还有另一个版本..没有iter函数



const rot13=(str) =>
{
    var alph= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let result ='';
    while(str.length>0)
  {

  for (let i=0;i<=25;i++)
     { 
       if ((alph[i]===str[0]) && (i>13)) {result = result + alph[i-13];};
       if ((alph[i]===str[0]) && (i<13)) {result = result + alph[i+13] ;} ;
      };
 if (!  /^[A-Z]*$/.test(str[0]) ) {result = result+ str[0];}; 
str=str.substring(1);
   };   
  return result;          
};

console.log(rot13('SERR YBIR?'));
// returns FREE LOVE?

我最近正处于开发 javascript 库的第一阶段,以简化我的日常编程需求。 其中之一是 加密

图书馆目前使用凯撒加密。

您可以 download 早期开发中的缩小版本并在您的 html 页面中使用它:

d(window).loaded(function() {

  /* *
   * Tidy up the heading
   * */
  d("h1")
    .background("#fafafa")
    .color("orange");

  /* *
   * Encrypt all paragraphs and maximize the height so we view each paragraph separately
   * */
  d("p")
    .encrypt(text = "", depth = 15)
    .resize("60%", "50px");

  /* *
   * Show up the first paragraph element's html
   * */
  _.popUp("First Paragraph: <hr>" + dom("p").getText(), "", "purple")
})

/* *
 * Show the inputed text in below snippet
 * */
function showEncryptedText(){
    d("#encrypted")
    .encrypt(d("#plain").c[0].value, 15)
    .background("#e8e8e8")
    .resize("100%", "100px");

}
<!DOCTYPE HTML>
<html>

<head>
  <title>Element Encryption</title>
  <script type="text/javascript" src="https://raw.githubusercontent.com/Amin-Matola/domjs/master/dom-v1.0.0/dom.min.js"></script>
</head>

<body>
  <h1>Javascript Encryption</h1>

  <p>This is the first paragraph you may encrypt</p>
  <p>This is another paragraph you may encrypt</p>
  <p>You may encrypt this too</p>
  <h2>You may even provide your text to be encrypted</h2>
  <div id="encrypted">
  
  </div>
  
  <input type="text" id="plain" value="" name="mydata" oninput="showEncryptedText()"/>
  </div>

  <footer>
    <!--- you may place your js here --->
    <script type="text/javascript">
    </script>
</body>

</html>

2020 TypeScript 版本:

  • 必须给出 shift 参数,但您可以为 rot13 或任何其他数字选择 13
// TypeScript Type: Alphabet
type Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

// Helper Function: Caesar Cipher
export const caesarCipher = (string: string, shift: number) => {
  // Alphabet
  const alphabet: Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

  // Encoded Text
  let encodedText: string = '';

  // Adjust Shift (Over 26 Characters)
  if (shift > 26) {
    // Assign Remainder As Shift
    shift = shift % 26;
  }

  // Iterate Over Data
  let i: number = 0;
  while (i < string.length) {
    // Valid Alphabet Characters
    if (alphabet.indexOf(string[i]) !== -1) {
      // Find Alphabet Index
      const alphabetIndex: number = alphabet.indexOf((string[i]).toUpperCase());

      // Alphabet Index Is In Alphabet Range
      if (alphabet[alphabetIndex + shift]) {
        // Append To String
        encodedText += alphabet[alphabetIndex + shift];
      }
      // Alphabet Index Out Of Range (Adjust Alphabet By 26 Characters)
      else {
        // Append To String
        encodedText += alphabet[alphabetIndex + shift - 26];
      }
    }
    // Special Characters
    else {
      // Append To String
      encodedText += string[i];
    }

    // Increase I
    i++;
  }

  return encodedText;
};

示例 #1:

console.log(caesarCipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 2));

Output:
CDEFGHIJKLMNOPQRSTUVWXYZAB

示例 #2:

console.log(caesarCipher('GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.', 26 + 13));

Output:
THE QUICK BROWN DOG JUMPED OVER THE LAZY FOX.

使用取模运算符;使句子大写;

function cipherRot13(str) {
  str = str.toUpperCase();
  return str.replace(/[A-Z]/g, rot13);

  function rot13(correspondance) {
    const charCode = correspondance.charCodeAt();
    //A = 65, Z = 90
    return String.fromCharCode(
            ((charCode + 13) <= 90) ? charCode + 13
                                    : (charCode + 13) % 90 + 64
           );
    
  }
}

我最近刚刚解决了一个与您的 rot13 类似的凯撒密码算法问题,但会将任何整数值作为移位参数。我注意到您的代码存在的一个问题是,您已经通过为 'i' 处的字符分配 charCode 将 temp 分配为数字。这会使您的条件过时,因为它永远不会识别字符串值,因为您传递的是数字值。此外,当您构建字符串时,它应该只是 'String.fromCharCode(13 + temp)'。我个人更喜欢凯撒密码,因为你可以分配随机移位参数。

这是我如何编写的示例:

// s = string to encrypt, k = shift value
// s = 'SERR PBQR PNZC' and k = 13 will produce 'FREE CODE CAMP'
const caesarCipher = function(s, k) {
  let result = '';
  
  for (let i = 0; i < s.length; i++) {

    let charCode = s[i].charCodeAt();
    // check that charCode is a lowercase letter; automatically ignores non-letters
    if (charCode > 96 && charCode < 123) {
      
      charCode += k % 26 // makes it work with numbers greater than 26 to maintain correct shift
      // if shift passes 'z', resets to 'a' to maintain looping shift
      if (charCode > 122) {
        charCode = (charCode - 122) + 96;
      // same as previous, but checking shift doesn't pass 'a' when shifting negative numbers
      } else if (charCode < 97) {
        charCode = (charCode - 97) + 123;
      }
    }

    if (charCode > 64 && charCode < 91) {
      
      charCode += k % 26
      
      if (charCode > 90) {
        charCode = (charCode - 90) + 64;
      } else if (charCode < 65) {
        charCode = (charCode - 65) + 91;
      }
    }

    result += String.fromCharCode(charCode);
  }
  return result
}

我努力让它变得简单,我赢得了免费披萨!。检查我的解决方案。

    function rot13(str) {
    
    var alphabets =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'," ", "-", "_", ".", "&","?", "!", "@", "#", "/"];
    
    var alphabets13 = ['N','O','P','Q','R','S','T','U','V','W','X','Y','Z','A','B','C','D','E','F','G','H','I','J','K','L','M', " ", "-", "_", ".", "&","?", "!", "@", "#", "/"];
    
    var resultStr = [];
    for(let i=0; i<str.length; i++){
        for(let j =0; j<alphabets.length; j++){
            if(str[i] === alphabets[j]){
            resultStr.push(alphabets13[j]);
            }
        }
    }
    return resultStr.join("");
  };

  rot13("SERR CVMMN!");

注意 : 此函数将处理字母(a-z 或 A-Z),所有其他将被忽略。

考虑的要点是

  1. 处理负数

  2. 可以照顾大数。

  3. 处理特殊字符,数字和space将按原样打印 标准差

    function caesarCipher(word, next) { 下一个 = 下一个 % 26; 让 res = ""; for (const letter of word) {

    let letterCode = letter.charCodeAt(0);
    if (letterCode >= 65 && letterCode <= 90) {
      letterCode = letterCode + next;
      if (letterCode > 90) {
        letterCode = letterCode - 26;
      } else if (letterCode < 65) {
        letterCode = letterCode + 26;
      }
    } else if (letterCode >= 97 && letterCode <= 122) {
      letterCode = letterCode + next;
    
      if (letterCode > 122) {
        letterCode = letterCode - 26;
      } else if (letterCode < 97) {
        letterCode = letterCode + 26;
      }
    }
    
        res = res + String.fromCharCode(letterCode);
      }
    
    return res;  }
    
    console.log(caesarCipher("Zoo  Keeper 666  %^&*(", 2));
    console.log(caesarCipher("Big Car", -16));
    

输出

Bqq  Mggrgt 666  %^&*(
Lsq Mkb

我刚刚用这个算法解决了 caesar chipper 问题。

function rot13(str) {
const rot13 = {
  'N': "A",
  'O': 'B',
  'P': 'C',
  'Q': 'D',
  'R': 'E',
  'S': 'F',
  'T': 'G',
  'U': 'H',
  'V': 'I',
  'W': 'J',
  'X': 'K',
  'Y': 'L',
  'Z': 'M',
  'A': 'N',
  'B': 'O',
  'C': 'P',
  'D': 'Q',
  'E': 'R',
  'F': 'S',
  'G': 'T',
  'H': 'U',
  'I': 'V',
  'J': 'W',
  'K': 'X',
  'L': 'Y',
  'M': 'Z'
}
const splitStr = str.split(' ').map(string => {
  return string.split('').map(string => rot13[string] === undefined ? string : rot13[string]).join('');
}).join(' ');
  return splitStr;
}

我看到这里的人写了很长的代码。我已经使用简单的解决方案解决了这个问题。

function replacing(str){
let strAm = "ABCDEFGHIJKLMNOPQRSTUVWXYZ -_.&?!@ #/";
let strNz = "NOPQRSTUVWXYZABCDEFGHIJKLM -_.&?!@ #/";
  let rot13 = '';
  for (let i = 0; i < str.length; i++){
    if (strAm.includes(str.charAt(i))){
      rot13 += str.charAt(i).replace(str.charAt(i), strNz[strAm.indexOf(str.charAt(i))]);
    }
  }
  return rot13;
}
console.log(replacing("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT."));

这是一个简单的解决方案。

function caesar(str) {

    str = str.split("")
    str = str.map(char => {
                            
        let code = char.charCodeAt(0)

        if( (code > 64 && code < 78) || (code > 96 && code < 110) )
            code += 13

        else if ( (code > 77 && code < 91) || (code > 109 && code < 123) )
            code -= 13
        
        return String.fromCharCode(code)
    })

    return str.join("")
}

这个问题可以通过多种方式解决。 下面是使用字符串中字符的 ASCII 代码和两个内置 JavaScript 函数的代码,即 charCodeAt() 和 String.fromCharCode()

function rot13(message) {
let cipherString = '';
let arr = [...message];
for (let i = 0; i < arr.length; i++) {
    let asciiValue = arr[i].charCodeAt();
    if (
        (asciiValue >= 65 && asciiValue <= 90) ||
        (asciiValue >= 97 && asciiValue <= 122)
    ) {
        if (asciiValue >= 65 && asciiValue <= 90) {
            if (asciiValue <= 77) {
                asciiValue += 13;
            } else {
                asciiValue -= 13;
            }
        } else {
            if (asciiValue <= 109) {
                asciiValue += 13;
            } else {
                asciiValue -= 13;
            }
        }
        cipherString += String.fromCharCode(asciiValue);
    } else cipherString += arr[i];
}
return cipherString;

}

我想post用我的方式在打字稿中做到这一点。

    function caesarCipher(s: string, k: number): string {
        //[ [ 'A', 65 ], [ 'Z', 90 ], [ 'a', 97 ], [ 'z', 122 ] ]

        return [...s]
            .map(l => (l.charCodeAt(0)))
            .map(n => n >= 65 && n <= 90 ? ((n - 65 + k) % 26) + 65 : n)
            .map(n => n >= 97 && n <= 122 ? ((n - 97 + k) % 26) + 97 : n)
            .map(n => String.fromCharCode(n))
            .join("")
    }

使用for循环的解决方案,在每次迭代中检查字符是否为字母然后通过从其ascii码中减去13对其进行解码,如果解码后的字符不是字母(其ascii码小于65),则通过添加对其进行解码13个。

function rot13(str) {

  function isAlphabet(char) {
    return String(char).match(/[A-Z]/);
  }

  const chars = str.split("");

  for(let i = 0 ; i < chars.length; i++) {
    const char = chars[i];
    if(isAlphabet(char)) {
      const decoded = String.fromCharCode(char.charCodeAt() - 13);
      const decodedAlphabet = String.fromCharCode(char.charCodeAt() + 13);
      chars[i] = isAlphabet(decoded)? decoded : decodedAlphabet;
    }
  }

  return chars.join("")
}