-8

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..

Chirag Parmar
  • 833
  • 11
  • 26
  • 1
    I think you mean the value after `AAA999` is `AAB000`, not `AAZ000`. Also, this is not base 36 but 3 places of base 26 and 3 places of base 10. It is not clear at all what you are trying to do. You are expected to show us the code you have written and explain what you don't understand about it. – Jim Garrison Jul 05 '16 at 18:17
  • Have you looked at this? http://stackoverflow.com/questions/15735079/convert-from-one-base-to-another-in-java – Jonathan M Jul 05 '16 at 18:21
  • 1
    isnt the value after AAA999 -> AAA99A in base 36 ? – alexbt Jul 05 '16 at 18:21
  • Current algorithm converts string to character and does the character increment . – Chirag Parmar Jul 05 '16 at 18:27
  • Sorry, my bad. AAA999 should become AAB000. I need the algorithm in java, which increments the alphanumeric string effectively. – Chirag Parmar Jul 05 '16 at 18:29
  • ok, then it is not base 36 ? – alexbt Jul 05 '16 at 18:31
  • If I am not mistaken, base36 means A-Z (capital or small) and 0-9 digits..!! Is that correct? – Chirag Parmar Jul 05 '16 at 18:34
  • 1
    yes, but the "digit" after 9 is A.. so AAA999 would increment to AAA99A. – alexbt Jul 05 '16 at 18:35
  • No ....AAA999 will become AAB000... Likewise if the string is say AZZ999 then next sequence will be BAA000 – Chirag Parmar Jul 05 '16 at 18:42
  • Well I have asked the question in right manner. Still why downvote? I am here to find a solution. – Chirag Parmar Jul 06 '16 at 15:40
  • `I have asked the question …` Well, not formally. Neither the title nor any part of the post show the form of a question, with the possible exception of the terminating question mark. `I need some sort of mathematical solution so that I can do math and increment it easily without using character increment` You present a problem and put up constrictions that look impossible to meet: what `math` operates on mixed characters and digits? – greybeard Jul 09 '16 at 15:14
  • `Current algorithm converts string to character and does the character increment` - put that in the question and explain _why_ this is inadequate. Try to end the post with an interrogative sentence, and turn the title into a question, too. If/as you are still looking for an approach (if not a problem definition), "Java" doesn't play a role (and I don't expect it when it comes to implementation). Mentioning Java in the title when the first tag is `java` is redundant - some consider it annoying. – greybeard Jul 09 '16 at 15:19
  • (Come to think of it, `All alphabets are in uppercase and letters are from 0-9` reads funny - _All letters are in uppercase and digits are from 0-9_?) – greybeard Jul 09 '16 at 17:41

2 Answers2

8

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).

alexbt
  • 16,415
  • 6
  • 78
  • 87
0

[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.

greybeard
  • 2,249
  • 8
  • 30
  • 66
  • What you are suggesting is partially true. I know it's difficult that is why I end up here asking for the solution. – Chirag Parmar Jul 10 '16 at 07:00
  • Can you identify and describe parts that are _not_ true, in addition to presenting in no uncertain terms what is? While at it, look at the suggestions to improve your "question" (e.g., `how can AA010-AAA003 = 7, the 3 [`A`s versus 2 `A`s do not] matter?` ([Alex](http://stackoverflow.com/a/38210171/3789665))) – greybeard Jul 10 '16 at 17:32
  • Thanks for pointing that. It was a typo. Actually it is AAA010-AAA003 = 7. – Chirag Parmar Jul 11 '16 at 08:51