3

I need to record SerialNumber(s) on an object. We enter many objects. Most serial numbers are strings - the numbers aren't used numerically, just as unique identifiers - but they are often sequential. Further, leading zeros are important due to unique id status of serial number.

When doing data entry, it's nice to just enter the first "sequential" serial number (eg 000123) and then the number of items (eg 5) to get the desired output - that way we can enter data in bulk see below:

Obj1.serial = 000123 Obj2.serial = 000124 Obj3.serial = 000125 Obj4.serial = 000126 Obj5.serial = 000127 

The problem is that when you take the first number-as-string, turn to integer and increment, you loose the leading zeros.

Not all serials are sequential - not all are even numbers (eg FDM-434\RRTASDVI908)

But those that are, I would like to automate entry.

In python, what is the most elegant way to check for leading zeros (*and, I guess, edge cases like 0009999) in a string before iterating, and then re-application of those zeros after increment?

I have a solution to this problem but it isn't elegant. In fact, it's the most boring and blunt alg possible.

Is there an elegant solution to this problem?

EDIT

To clarify the question, I want the serial to have the same number of digits after the increment.

So, in most cases, this will mean reapplying the same number of leading zeros. BUT in some edge cases the number of leading zeros will be decremented. eg: 009 -> 010; 0099 -> 0100

4
  • 2
    Do you know the length of the field a priori? It sounds like you're trying to calculate it based on one serial number given. If you do know the length of the field you're trying to generate, say 6, then '%06d' % n is hard to beat for elegance. Commented Mar 16, 2014 at 22:00
  • 1
    If you don't, ('%0'+str(len(ser))+'d')% (1+int(ser)) is still a oneliner… Commented Mar 16, 2014 at 22:09
  • No, unfortunately the length of any particular serial or group of serials is variable. Commented Mar 16, 2014 at 22:20
  • I like @fredtantini's answer here - I'll have to check it. Yep, I really like that answer. Can you break it down a little? Commented Mar 16, 2014 at 22:20

3 Answers 3

3

Try str.zfill():

>>> s = "000123" >>> i = int(s) >>> i 123 >>> n = 6 >>> str(i).zfill(n) '000123' 
Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunately, there is no set length for serial numbers. We run a warehouse of items from across the globe. Some serial numbers are 2 digits, some are 15. The field is a 40 char string.
@datakid: str(i).zfill(len(s)), then.
2

I develop my comment here, Obj1.serial being a string:

Obj1.serial = "000123" ('%0'+str(len(Obj1.serial))+'d') % (1+int(Obj1.serial)) 

It's like @owen-s answer '%06d' % n: print the number and pad with leading 0.

Regarding '%d' % n, it's just one way of printing. From PEP3101:

In Python 3.0, the % operator is supplemented by a more powerful string formatting method, format(). Support for the str.format() method has been backported to Python 2.6.

So you may want to use format instead… Anyway, you have an integer at the right of the % sign, and it will replace the %d inside the left string.

'%06d' means print a minimum of 6 (6) digits (d) long, fill with 0 (0) if necessary.

As Obj1.serial is a string, you have to convert it to an integer before the increment: 1+int(Obj1.serial). And because the right side takes an integer, we can leave it like that.

Now, for the left part, as we can't hard code 6, we have to take the length of Obj1.serial. But this is an integer, so we have to convert it back to a string, and concatenate to the rest of the expression %0 6 d : '%0'+str(len(Obj1.serial))+'d'. Thus

('%0'+str(len(Obj1.serial))+'d') % (1+int(Obj1.serial)) 

Now, with format (format-specification):

'{0:06}'.format(n) 

is replaced in the same way by

('{0:0'+str(len(Obj1.serial))+'}').format(1+int(Obj1.serial)) 

1 Comment

To be fair, I worked it out on my own reading once I settled down - I still see klingon when I read a one liner. I really need to concentrate to break it down.
2

You could check the length of the string ahead of time, then use rjust to pad to the same length afterwards:

>>> s = "000123" >>> len_s = len(s) >>> i = int(s) >>> i 123 >>> str(i).rjust(len_s, "0") '000123' 

You can check a serial number for all digits using:

if serial.isdigit(): 

5 Comments

" then re-application of those zeros after increment?" I think that 009 + 1 won't be 0010 but 010. The increment could change the length of the leading 0…
You are correct @fredtantini that's why I mentioned the edge cases
@fredtantini this will keep the field the same length; modification will be required if the OP wants the same number of leading zeros.
@jonrsharpe you are correct, and I was lazy in my explanation. Your answer is correct in so far as my question was poorly phrased, for which I apologise. My meaning was I wanted the same number of digits, with an appropriate number of leading zeros.
@datakid no problem; I suggest you update the question with what you think should happen in your edge case, for clarity.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.