Alphanumeric increment algorithm in JAVA [closed]

2019-06-14 20:34发布

I need to implement alphanumeric increment algorithm like AAA001 should become AAA002 AAA999 should become AAB000 and so on.

All alphabets are in uppercase and letters are from 0-9. It can contain alphabet or letter at any position in the alphanumeric string.

There are some rules though, like some 000 or 666 should not come in a series. That can be done later on but I am in need of basic logic to implement the algorithm.

I see many people did not understand my question. Just imagine the Plate Number of a vehicle which is nothing but a alphanumeric series which can have some excluded characters like BB6660 -> 666, triple 6 in between is not allowed.

It should support different formats like-

    @@@##
    @#@@##
    1@#@@##
    @@@@####
    ##@@#@

    @ means alphabet A-Z
    # means numbers 0-9            

Examples:

    AFG99 + 1= AFH00
    A2GF23 + 1 = A2GF24
    1A9AU99 + 1 = 1A9AV00
    AAZZ9999 + 1 = ABAA0000
    11AA9Z + 1 = 11AB0A

I need some sort of mathematical solution so that I can do math and increment it easily without using character increment.

I also need the count between the two ranges like how many counts are there between AAA003 and AA010 ?

    AAA010 - AAA003 = 7 

I would appreciate the help..

2条回答
Luminary・发光体
2楼-- · 2019-06-14 21:17

Here's 3 solutions: the first two are somewhat arithmetic incrementations while the third is more a character manipulations.

The 3 implementations all pass the same unit tests:

 assertEquals("1DDA01A", MyClass.increment("1DDA00Z"));
 assertEquals("1A9AV00", MyClass.increment("1A9AU99"));
 assertEquals("AFH00", MyClass.increment("AFG99"));
 assertEquals("A2GF24", MyClass.increment("A2GF23"));
 assertEquals("ABAA0000", MyClass.increment("AAZZ9999"));
 assertEquals("11AB0A", MyClass.increment("11AA9Z"));

First:

public static String increment(String number) {
    Pattern compile = Pattern.compile("^(.*?)([9Z]*)$");
    Matcher matcher = compile.matcher(number);
    String left="";
    String right="";
    if(matcher.matches()){
         left = matcher.group(1);
         right = matcher.group(2);
    }
    number = !left.isEmpty() ? Long.toString(Long.parseLong(left, 36) + 1,36):"";
    number += right.replace("Z", "A").replace("9", "0");
    return number.toUpperCase();
}

Second:

public static String increment(String number) {
    Pattern compile = Pattern.compile("^(.*?)([0-9]*|[A-Z]*)$");
    Matcher matcher = compile.matcher(number);
    String remaining = number;
    String currentGroup = "";
    String result = "";

    boolean continueToNext = true;
        while (matcher.matches() && continueToNext) {
        remaining = matcher.group(1);
        currentGroup = matcher.group(2);
        int currentGroupLength = currentGroup.length();
        int base = currentGroup.matches("[0-9]*") ? 10 : 36;
        currentGroup = Long.toString(Long.parseLong("1" + currentGroup, base) + 1, base);  // The "1" if just to ensure that "000" doesn't become 0 (and thus losing the original string length)
        currentGroup = currentGroup.substring(currentGroup.length() - currentGroupLength, currentGroup.length());
        continueToNext = Long.valueOf(currentGroup, base) == 0;
        if (base == 36) {
            currentGroup = currentGroup.replace("0", "A");
        }

        result = currentGroup + result;
        matcher = compile.matcher(remaining);
    }

    result = remaining + result;
    return result.toUpperCase();
}

Third :

This works with your current "reqs". Compared to how the question what asked at the beginning, this is not just a "left-part composed of letter" + "right part composed of digits". Now, it's "anything goes", and letters roll from A to Z to A, while digits from 0 to 9 to 0. When a letter reaches Z, it is reset to A, then the digit/letter on its left is incremented.

If all numbers are incremented, it does not add a new digit on the left. You did not mention that in your question, but I'm sure you can figure this out from here:

public static String increment(String number) {
    char[] cars = number.toUpperCase().toCharArray();
    for (int i = cars.length - 1; i >= 0; i--) {
        if (cars[i] == 'Z') {
            cars[i] = 'A';
        } else if (cars[i] == '9') {
            cars[i] = '0';
        } else {
            cars[i]++;
            break;
        }
    }
    return String.valueOf(cars);
}

As for the "count", your example isn't sufficient to grasp the logic. Does it count only numbers ? what about the letters ? Does it follow a baseXx ?

how can AA010-AAA003 = 7, the 3 A's versus 2 A's do no matter ? I feel this is rather on you to understand what are your requirements (ie: homework..)

Technically, this answers the question as it was asked originally (with many modifications along the way).

查看更多
三岁会撩人
3楼-- · 2019-06-14 21:27

[doing] math and increment [alphanumerics] without using character increment can be decomposed into simpler problems: consider your "alphanumerics" integers coded with a mixed base. This would leave conversion from alphanumeric to integer, (math) operations (increment, count between: difference/subtraction) on integers, and conversion from integer to alphanumeric.
For integer, have a look at LongAdder. For the conversions, you need to keep a sequence of bases to use - I recommend to start from unit/the little end and just use something easily iterable and able to keep (small) integers. Going from alphanumeric to integer, start with zero. For each character, add its value. For a letter, keep the number of different letters (alphabet size, 26 with the Latin alphabet as used now) as the base to use for that place, for a digit the number of different digits (ten, usually). If another character follows, multiply by that base and repeat.
Conversion from integer to alphanumeric would be the usual divide&remainder (using the bases as kept) - with a catch: how do you handle a carry from the most significant position?

There are some rules though, like some 000 or 666 should not come in a series. That can be done later on and will kill math.

查看更多
登录 后发表回答