简体   繁体   中英

2d array out of bound exception in for-loop

I'm working on keyword columnar cipher and I keep getting array out of bound exception, I have tried debugging the code and try and catch to understand the problem but I couldn't!

public Decryption (String cipherText, String keyWord) {

      cipherText = cipherText.replaceAll("\\s+","");
      cipherText = cipherText.toUpperCase();
      cipherText = cipherText.trim();

      keyWord = keyWord.toUpperCase();

      int column = keyWord.length();

      int row = (cipherText.length() / keyWord.length());
        if (cipherText.length() % keyWord.length() != 0)
          row += 1;

      char [][] matrix = new char [row][column];

      int re = cipherText.length() % keyWord.length();
       for (int i = 0; i < keyWord.length() - re; i++)
         matrix[row - 1][keyWord.length() - 1 - i] = '*';

      char[] sorted_key = keyWord.toCharArray();
      Arrays.sort(sorted_key); 

      int p = 0, count = 0; 
      char[] cipher_array = cipherText.toCharArray();

      Map<Character,Integer> indices = new HashMap<>();

      for(int i = 0; i < column; i++){

       int last = indices.computeIfAbsent(sorted_key[i], c->-1);
        p = keyWord.indexOf(sorted_key[i], last+1);
          indices.put(sorted_key[i], p);

           for(int j = 0; j < row; j++){
            if (matrix[j][p] != '*') 
            matrix[j][p] = cipher_array[count];
                    count++; 
                }}
}

I'm getting the exception in:

matrix[j][p] = cipher_array[count];

there is a problem with the loop, if I start with j = 1 it doesn't give me the exception but I don't get the correct results (It doesn't print the last row)

The cipher text that I'm trying to decrypt:

YARUEDCAUOADGRYHOBBNDERPUSTKNTTTGLORWUNGEFUOLNDRDEYGOOAOJRUCKESPY

Keyword:

YOURSELF

The result I get when I start the loop with 1:

JUDGE YOURSELF ABOUT YOUR BACKGROUND KNOWLEDGE TO UNDERSTAND CRYP

What I'm supposed to get:

JUDGE YOURSELF ABOUT YOUR BACKGROUND KNOWLEDGE TO UNDERSTAND CRYPTOGRAPHY

I'm not precisely sure, because your code doesnt allow me to validate this (there is no easy way to check the output of the algorithm without digging in), so... I assume that solution is:

for (int j = 0; j < row; j++) {
            if (matrix[j][p] != '*'){
                matrix[j][p] = cipher_array[count];
                count++;
            }
        }

instead of:

for (int j = 0; j < row; j++) {
                if (matrix[j][p] != '*')
                    matrix[j][p] = cipher_array[count];
                    count++;

            }

I think that the strategy of appending '*' to the string in this case is not the way to go - like what you did. Better to append some character when you are building the grid.

Following this approach here is a fixed version of your code (check the comments in the code for the changed parts):

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Decryption {

    private final String result;

    public Decryption(String cipherText, String keyWord) {

        cipherText = cipherText.replaceAll("\\s+", "");
        cipherText = cipherText.toUpperCase();
        cipherText = cipherText.trim();

        keyWord = keyWord.toUpperCase();

        int column = keyWord.length();

        int row = (cipherText.length() / keyWord.length());
        if (cipherText.length() % keyWord.length() != 0)
            row += 1;

        int[][] matrix = new int[row][column];

        // Changed to calculate the irregular columns
        int re = column - (row * column - cipherText.length());

        char[] sorted_key = keyWord.toCharArray();
        Arrays.sort(sorted_key);

        int p, count = 0;
        char[] cipher_array = cipherText.toCharArray();

        Map<Character, Integer> indices = new HashMap<>();

        for (int i = 0; i < column; i++) {

            int last = indices.computeIfAbsent(sorted_key[i], c -> -1);
            p = keyWord.indexOf(sorted_key[i], last + 1);
            indices.put(sorted_key[i], p);

            // Changed: Detects the need of an extra character and fills it in case of need
            boolean needsExtraChar = p > re - 1;
            for (int j = 0; j < row - (needsExtraChar ? 1 : 0); j++) {
                matrix[j][p] = cipher_array[count];
                count++;
            }
            if(needsExtraChar) {
                matrix[row - 1][p] = '-';
            }
        }

        result = buildString(matrix);
    }

    public static void main(String[] args) {
        System.out.println(new Decryption("EVLNE ACDTK ESEAQ ROFOJ DEECU WIREE", "ZEBRAS").result);
        System.out.println(new Decryption("EVLNA CDTES EAROF ODEEC WIREE", "ZEBRAS").result);
        System.out.println(new Decryption("YARUEDCAUOADGRYHOBBNDERPUSTKNTTTGLORWUNGEFUOLNDRDEYGOOAOJRUCKESPY", "YOURSELF").result);
    }

    private String buildString(int[][] grid) {
        return Arrays.stream(grid).collect(StringBuilder::new, (stringBuilder, ints) -> Arrays.stream(ints).forEach(t -> {
            stringBuilder.append((char) t);
        }), (stringBuilder, ints) -> {
        }).toString().replace("-", "");
    }
}

If you run this, this will print:

WEAREDISCOVEREDFLEEATONCEQKJEU
WEAREDISCOVEREDFLEEATONCE
JUDGEYOURSELFABOUTYOURBACKGROUNDKNOWLEDGETOUNDERSTANDCRYPTOGRAPHY

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM