【问题标题】:Java, How to implement a Shift Cipher (Caesar Cipher)Java,如何实现移位密码(凯撒密码)
【发布时间】:2013-10-07 04:09:27
【问题描述】:

我想实现一个凯撒密码移位,将字符串中的每个字母增加 3。

我收到此错误:

possible loss of precision required char; found int

到目前为止,这是我的代码:

import java.util.Scanner;
import java.io.*;

public class CaesarCipher
{
    public static void main (String [] args) {

        char[] letters = {'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'};

        char[] message = "onceuponatime".toCharArray();
        char[] eMessage = new char[message.length];
        char shift = 3;

        //encrypting message
        for(int i = 0; i <= message.length; ++i)
        {
            eMessage[i] = (message[i] + shift) % (char) letters.length;
            System.out.println(x);               
        }              
    }
}

是什么导致了这个错误?如何实现凯撒密码移位以将字符串中的每个字母增加 3?

【问题讨论】:

  • 旁注:您的代码似乎没有使用import 语句,因此您应该删除它们。
  • 我看到其他错误,例如“eMessage[i] = (message[i] + shift) % (char) letters.length;”错误 - 类型不匹配:无法从 int 转换为 char,这在 System.out.println(x) 中很明显;这里 x 是未定义的。首先尝试删除这些错误...

标签: java encryption cryptography caesar-cipher


【解决方案1】:

Java Shift Caesar Cipher by shift 空格。

限制:

  1. 仅适用于 shift 参数中的正数。
  2. 仅适用于班次小于 26。
  3. 如果有超过几千个字符的正文,是否 += 会使计算机陷入瘫痪。
  4. 对字符进行强制转换,因此除了 ascii 字母之外的任何内容都会失败。
  5. 只允许字母 a 到 z。无法处理空格、数字、符号或 unicode。
  6. 代码重复计算的次数超过了它必须的次数,从而违反了 DRY(不要重复自己)原则。

伪代码:

  1. 遍历字符串中的每个字符。
  2. 向字符添加移位,如果它落在字母表的末尾,则从字母表中的字母数中减去移位 (26)
  3. 如果移位没有使字符脱离字母表的末尾,则将移位添加到字符。
  4. 将字符附加到新字符串上。返回字符串。

功能:

String cipher(String msg, int shift){
    String s = "";
    int len = msg.length();
    for(int x = 0; x < len; x++){
        char c = (char)(msg.charAt(x) + shift);
        if (c > 'z')
            s += (char)(msg.charAt(x) - (26-shift));
        else
            s += (char)(msg.charAt(x) + shift);
    }
    return s;
}

如何调用它:

System.out.println(cipher("abc", 3));  //prints def
System.out.println(cipher("xyz", 3));  //prints abc

【讨论】:

  • 如果你需要使用负数,你可以从 26 中减去它们(-3 的移位是 23)。
  • 这很好,但可能应该使用 StringBuilder 而不是附加到您的 String s。见:stackoverflow.com/questions/4645020/…
【解决方案2】:

下面的代码也处理大小写,并保留其他字符。

import java.util.Scanner;

public class CaesarCipher
{
    public static void main(String[] args)
    {
    Scanner in = new Scanner(System.in);
    int length = Integer.parseInt(in.nextLine());
    String str = in.nextLine();
    int k = Integer.parseInt(in.nextLine());

    k = k % 26;

    System.out.println(encrypt(str, length, k));

    in.close();
    }

    private static String encrypt(String str, int length, int shift)
    {
    StringBuilder strBuilder = new StringBuilder();
    char c;
    for (int i = 0; i < length; i++)
    {
        c = str.charAt(i);
        // if c is letter ONLY then shift them, else directly add it
        if (Character.isLetter(c))
        {
        c = (char) (str.charAt(i) + shift);
        // System.out.println(c);

        // checking case or range check is important, just if (c > 'z'
        // || c > 'Z')
        // will not work
        if ((Character.isLowerCase(str.charAt(i)) && c > 'z')
            || (Character.isUpperCase(str.charAt(i)) && c > 'Z'))

            c = (char) (str.charAt(i) - (26 - shift));
        }
        strBuilder.append(c);
    }
    return strBuilder.toString();
    }
}

【讨论】:

    【解决方案3】:

    警告是由于您尝试将整数 (int shift = 3) 添加到字符值。如果您想避免这种情况,可以将数据类型更改为 char

    char 是 16 位,int 是 32。

    char shift = 3;
    // ...
    eMessage[i] = (message[i] + shift) % (char)letters.length;
    

    顺便说一句,您可以简化以下内容:

    char[] message = {'o', 'n', 'c', 'e', 'u', 'p', 'o', 'n', 'a', 't', 'i', 'm', 'e'}; 
    

    收件人:

    char[] message = "onceuponatime".toCharArray();
    

    【讨论】:

    • 我把这一行改成了 (char)letters.length;我仍然收到同样的错误。
    • 你把shift的数据类型改成char了吗?
    【解决方案4】:

    实现凯撒密码的两种方法:

    选项 1: 将字符更改为 ASCII 数字,然后您可以增加值,然后将其恢复为新字符。

    选项 2:使用 Map 将每个字母映射到这样的数字。

    A - 0
    B - 1
    C - 2
    etc...
    

    使用地图,您不必每次都重新计算班次。然后,您可以通过以下映射将明文更改为加密。

    【讨论】:

      【解决方案5】:

      您好...我在 swing 中为凯撒密码创建了一个 java 客户端服务器应用程序...我创建了一个可以正确解密文本的新公式... 对不起,只有小写..!

      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import java.io.*;
      import java.net.*;
      import java.util.*;
      
      public class ceasarserver extends JFrame implements ActionListener {
          static String cs = "abcdefghijklmnopqrstuvwxyz";
          static JLabel l1, l2, l3, l5, l6;
          JTextField t1;
          JButton close, b1;
          static String en;
          int num = 0;
          JProgressBar progress;
      
          ceasarserver() {
              super("SERVER");
              JPanel p = new JPanel(new GridLayout(10, 1));
              l1 = new JLabel("");
              l2 = new JLabel("");
              l3 = new JLabel("");
              l5 = new JLabel("");
              l6 = new JLabel("Enter the Key...");
              t1 = new JTextField(30);
              progress = new JProgressBar(0, 20);
              progress.setValue(0);
              progress.setStringPainted(true);
              close = new JButton("Close");
              close.setMnemonic('C');
              close.setPreferredSize(new Dimension(300, 25));
              close.addActionListener(this);
              b1 = new JButton("Decrypt");
              b1.setMnemonic('D');
              b1.addActionListener(this);
              p.add(l1);
              p.add(l2);
              p.add(l3);
              p.add(l6);
              p.add(t1);
              p.add(b1);
              p.add(progress);
              p.add(l5);
              p.add(close);
              add(p);
              setVisible(true);
              pack();
          }
      
          public void actionPerformed(ActionEvent e) {
              if (e.getSource() == close)
                  System.exit(0);
              else if (e.getSource() == b1) {
                  int key = Integer.parseInt(t1.getText());
                  String d = "";
                  int i = 0, j, k;
                  while (i < en.length()) {
                      j = cs.indexOf(en.charAt(i));
                      k = (j + (26 - key)) % 26;
                      d = d + cs.charAt(k);
                      i++;
                  }
                  while (num < 21) {
                      progress.setValue(num);
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException ex) {
                      }
                      progress.setValue(num);
                      Rectangle progressRect = progress.getBounds();
                      progressRect.x = 0;
                      progressRect.y = 0;
                      progress.paintImmediately(progressRect);
                      num++;
                  }
                  l5.setText("Decrypted text: " + d);
              }
          }
      
          public static void main(String args[]) throws IOException {
              new ceasarserver();
              String strm = new String();
              ServerSocket ss = new ServerSocket(4321);
              l1.setText("Secure data transfer Server Started....");
              Socket s = ss.accept();
              l2.setText("Client Connected !");
              while (true) {
                  Scanner br1 = new Scanner(s.getInputStream());
                  en = br1.nextLine();
                  l3.setText("Client:" + en);
              }
          }
      

      客户端类:

      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import java.io.*;
      import java.net.*;
      import java.util.*;
      
      public class ceasarclient extends JFrame {
          String cs = "abcdefghijklmnopqrstuvwxyz";
          static JLabel l1, l2, l3, l4, l5;
          JButton b1, b2, b3;
          JTextField t1, t2;
          JProgressBar progress;
          int num = 0;
          String en = "";
      
          ceasarclient(final Socket s) {
              super("CLIENT");
              JPanel p = new JPanel(new GridLayout(10, 1));
              setSize(500, 500);
              t1 = new JTextField(30);
              b1 = new JButton("Send");
              b1.setMnemonic('S');
              b2 = new JButton("Close");
              b2.setMnemonic('C');
              l1 = new JLabel("Welcome to Secure Data transfer!");
              l2 = new JLabel("Enter the word here...");
              l3 = new JLabel("");
              l4 = new JLabel("Enter the Key:");
              b3 = new JButton("Encrypt");
              b3.setMnemonic('E');
              t2 = new JTextField(30);
              progress = new JProgressBar(0, 20);
              progress.setValue(0);
              progress.setStringPainted(true);
              p.add(l1);
              p.add(l2);
              p.add(t1);
              p.add(l4);
              p.add(t2);
              p.add(b3);
              p.add(progress);
              p.add(b1);
              p.add(l3);
              p.add(b2);
              add(p);
              setVisible(true);
              b1.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      try {
                          PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
                          pw.println(en);
                      } catch (Exception ex) {
                      }
                      ;
                      l3.setText("Encrypted Text Sent.");
                  }
              });
              b3.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      String strw = t1.getText();
                      int key = Integer.parseInt(t2.getText());
                      int i = 0, j, k;
                      while (i < strw.length()) {
                          j = cs.indexOf(strw.charAt(i));
                          k = (j + key) % 26;
                          en = en + cs.charAt(k);
                          i++;
                      }
                      while (num < 21) {
                          progress.setValue(num);
                          try {
                              Thread.sleep(100);
                          } catch (InterruptedException exe) {
                          }
                          progress.setValue(num);
                          Rectangle progressRect = progress.getBounds();
                          progressRect.x = 0;
                          progressRect.y = 0;
                          progress.paintImmediately(progressRect);
                          num++;
                      }
                  }
              });
              b2.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      System.exit(0);
                  }
              });
              pack();
          }
      
          public static void main(String args[]) throws IOException {
              final Socket s = new Socket(InetAddress.getLocalHost(), 4321);
              new ceasarclient(s);
          }
      }
      

      【讨论】:

        【解决方案6】:

        //我们可以使用char作为整数,因为Java将每个字符存储为ascii整数

        String rotationCipher(String input, int rotationFactor){

            char [] inputArr = input.toCharArray();
        
            String resultStr = "";
        
            for (char ch: inputArr ) {
                if(ch < 58 && ch>48){
                    int withRotetionFactor = ch + rotationFactor;
                    if(withRotetionFactor < 57){
                      resultStr = resultStr + (char) withRotetionFactor;
                   }else {
                         int looprotation =  withRotetionFactor - 10;
                        resultStr = resultStr + (char)looprotation;
                    }
                }else  if(ch < 91 && ch>63){
                    int withRotetionFactor = ch + rotationFactor;
                    if(withRotetionFactor < 91){
                        resultStr = resultStr + (char) withRotetionFactor;
                    }else {
                        int looprotation =  withRotetionFactor - 26;
                        resultStr = resultStr + (char)looprotation;
                    }
                }else if(ch < 123 && ch>96){
                    int withRotetionFactor = ch + rotationFactor;
                    if(withRotetionFactor < 123){
                        resultStr = resultStr + (char) withRotetionFactor;
                    }else {
                        int looprotation =  withRotetionFactor - 26;
                        resultStr = resultStr + (char)looprotation;
                    }
                }else {
                    resultStr = resultStr + ch;
                }
        
        
        
            }
            return resultStr;
        
        }
        

        【讨论】:

        • 我建议将“幻数”更改为相应的 ASCII 字符。像 58 和 123 这样的数字不像 ':' 和 '{' 那样明显。
        【解决方案7】:

        这是我的 Java Stream API 实现的一个可以使用凯撒密码进行加密的程序:

        public String encrypt(String plaintext) {
          return plaintext.toLowerCase().chars()
            .mapToObj(plaintextLetter -> plaintextLetter == ' ' ? ' ' : applyEncryptionAlgorithm(plaintextLetter))
            .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
            .toString()
            .toUpperCase();  // convention - ciphertext is in uppercase
        }
        
        private int applyEncryptionAlgorithm(int plaintextLetter) {
          plaintextLetter -= 'a';
          int ciphertextLetter = (plaintextLetter + 3) % 26;
          return ciphertextLetter + 'a';
        }
        

        还有一个单元测试:

        @Test
        public void testEncrypt() {
          String plaintext = "meet me after the toga party";
          String ciphertext = "PHHW PH DIWHU WKH WRJD SDUWB";
        
          String result = caesarCipher.encrypt(plaintext);
        
          assertEquals(ciphertext, result);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-09-28
          • 2021-03-01
          • 1970-01-01
          • 2016-08-30
          • 1970-01-01
          • 2017-02-08
          • 2014-03-07
          • 2014-06-24
          相关资源
          最近更新 更多