Andrew
Andrew

Reputation: 75

Filling a specific String format with zeros if it is shorter than the required length

I'm trying to create a program that checks to see whether the user's serial codes are valid or not. It should comply to a specific format. The format should be two numbers, followed by a dash, four numbers, a dot, then four numbers and two characters (note: characters accepted are only a, b and c).

Example valid format:

31-0001.2341ac
00-9999.0001cb

If the serial code is invalid because it didn't meet the required length of string, the program should fill it with zeros at the beginning and the new code will be printed.

I managed to work with the serial code checker using regular expressions, it is now correctly verifying whether the code is valid or not. However, I find it challenging when it needs to generate a new code for an invalid serial code. It's like I need to hard code for all possible combinations.

I tried following this How to format a Java string with leading zero?, but I'm having a hard time because my String format has dash & dot in the middle of the string.

I'm still fairly new, I am not yet familiar with utils or libraries for such functions. I hope someone can help me fix my code to make it simpler and more efficient.

import java.util.Scanner;

public class SerialCheck {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("How many serial numbers would you like to check: ");
        int length = sc.nextInt();
        int valid = 0;

        String[] sSerials = new String[length];

        for (int nCtr = 0; nCtr < length; nCtr++) {
            System.out.print("Enter Serial " + (nCtr + 1) + ": ");
            sSerials[nCtr] = sc.next();
        }

        System.out.println();
        System.out.println("The following were added: ");
        for (int nCtr = 0; nCtr < length; nCtr++) {
            System.out.println(sSerials[nCtr]);
        }

        System.out.println();
        System.out.println("Comments\t" + "New Code");
        for (int nCtr = 0; nCtr < length; nCtr++) {
            boolean isValid = sSerials[nCtr].matches("[0-9]{2}-[0-9]{4}\\.[0-9]{4}[abc0-9]{2}");
            boolean isMissing = sSerials[nCtr].matches("[0-9]{2}-[0-9]{4}\\.[0-9]{1}[abc0-9]{2}") ||
                sSerials[nCtr].matches("[0-9]{2}-[0-9]{4}\\.[0-9]{2}[abc0-9]{2}") ||
                sSerials[nCtr].matches("[0-9]{2}-[0-9]{4}\\.[0-9]{3}[abc0-9]{2}");
            boolean isMissing1 = sSerials[nCtr].matches("[0-9]{2}-[0-9]{1}\\.[0-9]{4}[abc0-9]{2}") ||
                sSerials[nCtr].matches("[0-9]{2}-[0-9]{2}\\.[0-9]{4}[abc0-9]{2}") ||
                sSerials[nCtr].matches("[0-9]{2}-[0-9]{3}\\.[0-9]{4}[abc0-9]{2}");
            boolean isMissing2 = sSerials[nCtr].matches("[0-9]{0}-[0-9]{4}\\.[0-9]{4}[abc0-9]{2}") ||
                sSerials[nCtr].matches("[0-9]{1}-[0-9]{4}\\.[0-9]{4}[abc0-9]{2}");

            if (isValid) {
                System.out.println("Valid\t\t" + sSerials[nCtr]);
            } else if (isMissing) {
                System.out.println("Invalid\t\t" + sSerials[nCtr].substring(0, 8) + "0000".substring(0, 14 - sSerials[nCtr].length()) + sSerials[nCtr].substring(8));
            } else if (isMissing1) {
                System.out.println("Invalid\t\t" + sSerials[nCtr].substring(0, 3) + "0000".substring(0, 14 - sSerials[nCtr].length()) + sSerials[nCtr].substring(3));
            } else if (isMissing2) {
                System.out.println("Invalid\t\t" + sSerials[nCtr].substring(0, 0) + "00".substring(0, 14 - sSerials[nCtr].length()) + sSerials[nCtr].substring(0));
            } else {
                System.out.println("Invalid\t");
            }
        }
    }
}

Upvotes: 2

Views: 486

Answers (2)

Jon Thoms
Jon Thoms

Reputation: 10749

Basically, your strategy of determining specifically what was missing is incorrect. A different approach would be to just pad full of zeros until the right length is achieved, then replace each character as needed if too short or if format is broken. Note also that the original question didn't take into account if the string is too long, so I just assumed that you can treat it as all zeros for simplicity sake. Also see code example with sample inputs at JDoodle. See the code example below:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;

public class SerialCheck {

  private static String leftPadWithX(String shortStr) {
    StringBuilder paddableString = new StringBuilder(shortStr);
    for (int i = 14 - shortStr.length(); i > 0; --i) {
      paddableString.insert(0, 'X');
    }
    assert paddableString.length() == 14;
    return paddableString.toString();
  }

  private static String fix(String broken) {
    assert broken.length() == 14;
    StringBuilder mutableBroken = new StringBuilder(broken);
    for(int i = 0; i < 14; ++i) {
      // not exactly a char, but need a 1 element string for regex matching
      String brokenChar = "" + mutableBroken.charAt(i);
      if (i < 2 && !Pattern.matches("\\d", brokenChar)) {
        mutableBroken.replace(i, i+1, "0");
      } else if (i == 2 && !Pattern.matches("-", brokenChar)) {
        mutableBroken.replace(i, i+1, "-");
      } else if (i > 2 && i < 7 && !Pattern.matches("\\d", brokenChar)) {
        mutableBroken.replace(i, i+1, "0");
      } else if (i == 7 && !Pattern.matches("\\.", brokenChar)) {
        mutableBroken.replace(i, i+1, ".");
      } else if (i > 7 && i < 12 && !Pattern.matches("\\d", brokenChar)) {
        mutableBroken.replace(i, i+1, "0");
      } else if (i >= 12 && i < 14 && !Pattern.matches("[abc\\d]", brokenChar)) {
        mutableBroken.replace(i, i+1, "0");
      }
    }
    return mutableBroken.toString();
  }

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    System.out.print("How many serial numbers would you like to check: ");
    int length = sc.nextInt();
    int valid = 0;

    String[] sSerials = new String[length];

    for (int nCtr = 0; nCtr < length; nCtr++) {
      System.out.print("Enter Serial " + (nCtr + 1) + ": ");
      sSerials[nCtr] = sc.next();
    }

    System.out.println();
    System.out.println("The following were added: ");
    for (int nCtr = 0; nCtr < length; nCtr++) {
      System.out.println(sSerials[nCtr]);
    }

    System.out.println();
    System.out.println("Comments\t" + "New Code");
    for (int nCtr = 0; nCtr < length; nCtr++) {
      boolean isValid = sSerials[nCtr].matches("[0-9]{2}-[0-9]{4}\\.[0-9]{4}[abc0-9]{2}");
    if (isValid) {
      System.out.println("Valid\t\t" + sSerials[nCtr]);
    } else if (sSerials[nCtr].length() > 14) {
      // if too long, create all padded zeros
      System.out.println("Invalid\tToo long\t00-0000.000000");
    } else if (sSerials[nCtr].length() < 14) {
      // too short, pad with 0s unconditionally and fix format
      String xPadded = leftPadWithX(sSerials[nCtr]);
      String fixed = fix(xPadded);
      System.out.println("Invalid\tToo short\t" + fixed);
    } else {
      // right length but bad format
      String fixed = fix(sSerials[nCtr]);
      System.out.println("Invalid\tBad format\t" + fixed);
      }
    }
  }
}

Upvotes: 1

lexicore
lexicore

Reputation: 43671

Your problem actually has two parts here.

First part is parsing the - possibly invalid - input.

The second part is formatting it with leading zeroes.

The second part is fairly easy. You just create a character array of length 12, fill it with zeroes, then fill it with your data (starting at the end), create three strings out of it and just s0 + "-" + s1 + "." + s0.

The first part can be as easy or as difficult you want it. Are - and . significant delimiters?

If not, just remove them from the string and you have your result (well, to be converted to char array yet).

If yes, what happens if these delimiters are missing? What happens if delimited part is longer than intended? My point is, you first need to define rules for parsing. Once you do this you will have a good idea how parsing should be implemented.

Upvotes: 0

Related Questions