凯撒密码移位字母问题

问题描述 投票:0回答:4

我正在尝试使用 ASCII 转换器逐个字母转换技术来编写凯撒密码,然后移动数字并在文本中再次转换它们,但只有当字母不超过 z 时它才有效。

const checkPunctuation = (text) => {
  return /[.,#!$%^&*;:{}=\-_`~()]/g.test(text);
};

const ASCIIConverter = (text) => {
  return text.split("").map((char) => {
    return checkPunctuation(char) ? char : char.charCodeAt();
  });
};

const caesarCipher = (text, shift) => {
  return ASCIIConverter(text)
    .map((code) => (code + shift) % 26)
    .map((charCode) => String.fromCharCode(charCode))
    .join("");
};
console.log(caesarCipher("pizza!", 2));

预期:wpggh!

收到:(带标记的方框字符

javascript unit-testing encryption caesar-cipher codesandbox
4个回答
0
投票

charCodeAt 可能只是返回 ASCII 中的索引。您需要的是 [0..n) 范围内的索引,在本例中 n 是 26。与 fromCharCode 相同的问题当然是在应用 %26 后接收到微小的值。通常,您可以减去/添加 Aa 的值以使值进入正确的范围。

一般来说,我建议添加将 ASCII 索引转换为字母表索引并再次转换回来的方法。这些可以单独测试。这种高度简洁的代码的问题是调试起来很糟糕;映射“流”中的值时会发生太多事情。


0
投票

一个问题是代码错误地减少了值。 比如A的charcode是65,变成了20。 如果大小写无关紧要,您可以使用

String.fromCharCode((charCode - 65)%26 + 65)

这会将值置于大写字母的正确范围内。


0
投票

一些问题:

  • 有成千上万的字符不是字母,也不在您的标点符号正则表达式中。最好检查 letters:如果它不是英文字母表中的字符,则保持不变。

  • return checkPunctuation(char) ? char : char.charCodeAt() 是个坏主意:这意味着映射是混合类型:字符串(原始字符)或数字(它的代码点)。这会影响对这些值的进一步处理。见下一点

  • .map((code) => (code + shift) % 26) 期望 code 是一个数字,但它也可以是一个字符(标点符号,见上一点),然后 + shift 将执行字符串连接,在这种情况下 % 26 将产生 NaN。这显然不是预期的。

  • .map((code) => (code + shift) % 26) 产生 0 到 25(和 NaN)之间的数字,这不是字母的 ASCII 码,而是控制字符。

  • .map((charCode) => String.fromCharCode(charCode)) 会将控制代码(和 NaN)转换为它们的字符表示,也就是您看到的那些框。在转换为字符串之前,您需要将字母 'a' 的 ASCII 码添加回它。

  • 示例调用错误。移动 2 不会给出“wpggh!”结果。为此,您需要使用 7 的移位(因为“w”出现在字母表中字母“p”之后的 7 个字母)。

这里是建议的更正:

const convertRange = (text, regex, a, shift) =>
  text.replace(regex, letter => 
    String.fromCharCode(
      (letter.charCodeAt() - a.charCodeAt() + shift) % 26 + a.charCodeAt()
    )
  );

const caesarCipher = (text, shift) => {
  text = convertRange(text, /[A-Z]/g, 'A', shift); // Cypher uppercase
  return convertRange(text, /[a-z]/g, 'a', shift); // Cypher lowercase
};

console.log(caesarCipher("pizza!", 7));


0
投票

这是一个有效的 Caesar's Cypher 函数,它将仅旋转 ASCII 字符 [A-Z] 和 [a-z]:

function cc(str,n){
 return str.split("").map(c=>{
  let a=c.charCodeAt(0)-1
  if (a>63&&a<90||a>95&&a<122){
   let off=64+Math.floor(a/96)*32
   a=(a%32+n)%26+off;
  }
  return String.fromCharCode(a+1);
 }).join("");
}

console.log(cc("Most fabulous - our Pizzas!",7));

© www.soinside.com 2019 - 2024. All rights reserved.