0

Trying to create a simple caesar cipher ... It fails to work on all characters i.e {,},& etc. How can I modify my code to accomodate all characters possible including Chinese characters

  String caesar(String text, int key, int encrypt) {
    String result = "";

    for (var i = 0; i < text.length; i++) {
      int ch = text.codeUnitAt(i), offset, x;

      if (ch >= 'a'.codeUnitAt(0) && ch <= 'z'.codeUnitAt(0))
        offset = 97;
      else if (ch >= 'A'.codeUnitAt(0) && ch <= 'Z'.codeUnitAt(0))
        offset = 65;
      else if (ch == ' '.codeUnitAt(0)) {
        result += " ";
        continue;
      }

      if (encrypt == 1)
        x = (ch + key - offset) % 26;
      else
        x = (ch - key - offset) % 26;

      result += String.fromCharCode(x + offset);
    }
    return result;
  }


Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
I AM
  • 96
  • 1
  • 7

2 Answers2

0

You'd need to create an alphabet, consisting of a string of all possible characters, and replace 26 with the size of that alphabet (the ABC is just one Western oriented alphabet). Then you can use the zero-based index in the alphabet instead of ch - offset for each character.

You cannot use the same trick with the comparison with A and Z as the code points are not a continuous string of printable characters. That means that adding the key may result in a non-existent or unprintable character value. You could create two methods: toIndex(codeUnit) and toCodeUnit(index) so you can perform any calculation you wish though.

I presume you have enough characters within the normal Chinese character range. If you want to use rare Chinese characters that have a code point higher than 0xFFFF then you may have another problem to solve.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Do you know of a simple encryption technique that does not increase size of the original string ? – I AM Jun 21 '21 at 16:41
  • Above does not increase the size of the original string, at least not when it comes to the number of characters that are used from the alphabet. In UTF-8 it depends on the input and the key if it is larger or even smaller than the original. – Maarten Bodewes Jun 21 '21 at 21:01
  • The one time pad would also work, as would any stream cipher (with the caveat that you then cannot store the IV as that would expand the ciphertext ever so slightly, so you'd need a fresh key for each message). – Maarten Bodewes Jun 21 '21 at 21:39
0

Try it! This only works in english.

    import 'dart:io';

    // the preset alphabet
    List<String> alphabet = [
      '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'
    ];

    void main() {
      stdout.write("Enter the Caesar key: ");
      // if the entered k is null, then set k as 0
      var k = int.parse(stdin.readLineSync() ?? "0");
      stdout.write("Enter the plaintext: ");
      // not including the uppercase
      var plaintext = (stdin.readLineSync() ?? "").toLowerCase();
      var ciphertext = "";
      for (var char in plaintext.split('')) {
        // if the char is a letter, then match the alphabet
        if (char.contains(RegExp(r'[a-z]'))) {
          for (var i = 0; i < 26; i++) {
            if (alphabet[i] == char) {
              // if the matched letter is 26-k below, then find the letter over k interval
              if (i < 26 - k) {
                ciphertext += alphabet[i + k];
              } else {
                // if above, return the start point
                ciphertext += alphabet[i + k - 26];
              }
            }
          }
        } else {
          // if not, then simply add it
          ciphertext += char;
        }
      }
      print("The ciphertext is: $ciphertext");
    }
trigold
  • 51
  • 7