All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.gc.aafc.dina.translator.NumberLetterTranslator Maven / Gradle / Ivy

The newest version!
package ca.gc.aafc.dina.translator;

import java.util.regex.Pattern;

/**
 * Translates numbers to letters (alphabetical value for a number) and vice versa.
 *
 */
public final class NumberLetterTranslator {

  /**
   * regex for any character not in alphabet and capitalized.
   */
  private static final Pattern NON_ALPHABET_PATTERN = Pattern.compile("[^A-Z]");

  /**
   * Protect against a potential int overflow
   */
  public static final int MAX_SUPPORTED_LETTERS = 6;
  public static final int MAX_SUPPORTED_NUMBER = 321272406; // == "ZZZZZZ"

  /** Utility class This class should not be constructed. */
  private NumberLetterTranslator() { }

  /**
   * Generate the alphabetical value for a number, where the letters roll over after reaching Z.
   *
   * Examples: 1 -> A, 26 -> Z, 27 -> AA, 52 -> AZ
   *
   * @param givenNumber the number you want alphabetized, only non-null, non-zero,
   *            positive whole numbers.
   * @return the letter
   * @throws IllegalArgumentException the illegal argument exception
   */
  public static String toLetter(Integer givenNumber) {

    if (givenNumber == null) {
      return null;
    }

    if (givenNumber <= 0) {
      throw new IllegalArgumentException(
          "Does not accept Integers less than zero. Your input : " + givenNumber);
    }
    if (givenNumber > MAX_SUPPORTED_NUMBER) {
      throw new IllegalArgumentException(
              "Input should be less than " + MAX_SUPPORTED_NUMBER + ". Your input : " + givenNumber);
    }

    int number = givenNumber;

    // The following equation calculates the number of letters the character array
    // should have.
    // The formula is for converting to log base 26, as the range each additional
    // character adds
    // is exponential. I.e Integer Range 1-26 returns buf[1], Range 27-702 returns
    // buf[2] and so on.
    char[] buf = new char[(int) Math.floor(Math.log(25L * (number + 1)) / Math.log(26))];

    // for each element in buf, populate it with the correct character
    for (int i = buf.length - 1; i >= 0; i--) {
      number--;
      buf[i] = (char) ('A' + number % 26); // using ASCII with A as the starting point.
      number /= 26;
    }
    return new String(buf);
  }

  /**
   * Gets the number from an alphabetized number, where the letters roll over after reaching Z.
   *
   * Examples: A -> 1, Z -> 26, AA -> 27, AZ -> 52
   *
   * @param givenLetter the alphabetized number, A-Z alphabetical only
   * @return the number as an Integer
   */
  public static Integer toNumber(String givenLetter) {

    // If nothing is given, nothing is given back.
    if (givenLetter == null) {
      return null;
    }

    String letter = givenLetter.toUpperCase();

    if (NON_ALPHABET_PATTERN.matcher(letter).find()) {
      throw new IllegalArgumentException("Alphabetical[A-Z] Inputs only. Your input : " + letter);
    }

    if (letter.length() > MAX_SUPPORTED_LETTERS) {
      throw new IllegalArgumentException(
          "Input should have less than " + MAX_SUPPORTED_LETTERS + " letters. Your input : "
              + letter.length() + " letters");
    }

    int currIntValue = (int) letter.charAt(0) - 64;  // charAt returns the ASCII number and the alphabets start
    int currLetterIdx = 1;
    while (currLetterIdx < letter.length()) {
      currIntValue *= 26; //each iteration is a full alphabet round
      currIntValue += letter.charAt(currLetterIdx) - 64;
      currLetterIdx++;
    }

    return currIntValue;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy