Autopopulating text field with string and number combination

I have an attribute table with a text field which indicates a unique identifier for each row. The identifier includes a combination of text and numbers, sequentially increasing, as follows: PHOTO_0001.jpg, PHOTO_0002.jpg, PHOTO_0003.jpg, etc.

Some rows have been added to the table and this field is left blank, as you can see in the screenshot ("Name" field). How can I autopopulate this field to include the text and have the numbers sequentially increase in order to fill in these blanks? In other words, I'd like the first blank space to be filled with PHOTO_0005.jpg, and so on.

I'm familiar with ArcMap but very new to Python.

• If, for example, you had three rows with three values in a text field: PHOTO_0001.jpg, No Value, and PHOTO_0002.jpg. How would you name the second "No Value" row? I am unclear where the inserted rows are and how you want to handle naming those rows. A screenshot of the rows and your intended output would be helpful. – Aaron Jul 10 '15 at 18:37
• Auto-incrementing numbers is a topic well covered here, though filling in gaps in an existing sequence not so much. You might want to explore incrementing a number field and then concatenating it with a text field in a separate calculation/operation. – Chris W Jul 10 '15 at 20:17
• I've added a screenshot to the initial question, hopefully this helps make it more clear. I have auto-incremented before, so perhaps you're right that doing this in separate fields and combining them is the way to go, I was just wondering if there was a quicker solution. Thanks for your input. – eplanner Jul 10 '15 at 20:48

Based on the screenshot you've provided, it looks like you can do this really easily by using the OID field. Those integers match the photo numbers.

code block:

def makeName(oid):
n = 4 - len(str(oid))
return "PHOTO_{0}{1}.jpg".format(n*"0",str(oid))


expression:

makeName(!OID!)


Test this on a new string field to make sure it works, because it will overwrite all of your existing values. Again, this will only work in this specific case if you know you can count on those OIDs matching.

As @paul points out, the code above could be reduced to a single line in the expression.

"PHOTO_{:04d}.jpg".format(!OID!)


much cleaner than I what originally had.

As per the OP comment about OID not always working for this, here are a couple of things to keep in mind. First, with shapefiles/dbase tables, the OID/FID field will always be consecutive integers (regardless of deleted records), but gdb feature classes have an OBJECTID field that is not updated when records are deleted, so you could easily have 1, 2, 5, 7, 12, 13, 14, 15. So the code above would definitely not work with a gdb feature class... Second, using field calculator will always iterate through rows in the order of the OID field (as far as I know).

Therefore, if your data is in dbase/shp tables and your photos are sequentially numbered based beginning with 1 in the first row, then this method actually should be reliable.

That said, this will work independently of the OID field, but it's redundant unless you are using gdb feature classes or tables, because it's still iterating on OID, and OID is +1 integers.

code block:

n = 0
def fillIn(value):
global n
n+=1
if value = "":
return "PHOTO_{:04d}.jpg".format(n)
else:
return value


expression:

fillIn(!Name!)

• A much simpler way would to forgo using the code block entirely and instead use "PHOTO_{:04d}.jpg".format(!OID!) (Note that you don't need to str --- .format() does that automatically. – Paul Jul 10 '15 at 20:52
• yeah, good one. {:04d} is super cool, didn't know about that. – mr.adam Jul 10 '15 at 21:06
• Thanks that worked perfectly! Do you if it would be possible to do this in another way if the OID field didn't match up? There are quite a few attribute tables that need editing and I'm not sure if they will all match as this one does. – eplanner Jul 10 '15 at 21:11
• @mr.adam, there are tons of format specifiers that make life really simple. Some can be found here. – Paul Jul 10 '15 at 21:12
• @Paul, nice. the challenge is remembering to look harder next time, instead of using what I'm use to :). eplanner, I'll update my answer, though, like Chris W pointed out, there are lots of related answers out there already. – mr.adam Jul 10 '15 at 21:27

You don't need an expression in the Field Calculate codeblock. If the PhotoNumber matches the OID value for every record in your table, just Field Calculate:

"Photo_" + str(!OID!).rjust(4, "0") + ".jpg" using Python syntax

This is by far the simplest solution.

For symmetry, here is an Update Cursor approach that uses the zfill method to pad 0's.

import arcpy

fc = r'C:\path\to\your\fgdb.gdb\fc'

with arcpy.da.UpdateCursor(fc, ["OID@", "Name"]) as cursor:
for row in cursor:
row[1] = ''.join(['PHOTO_', str(row[0]).zfill(4), '.jpg'])
cursor.updateRow(row)