Base 26 (letters) and Base 10 using recursion I was messing around with base conversion between decimal and Base26 (alphabet) with no 0th case because I needed it for the Google Sheets API in order to find specific cell values from a 3 dimensional list of all of the entered cell values on a spreadsheet. Remember that with spreadsheets, the columns are counted with no 0th case and A == 1 Z == 26 BA == 53. 

Some test cases for conversion between the two bases would be

"zyz" == 18252, "aa" == 27, "zz" == 702 

When I went to go write the code, I looked for simple solutions, but could not find anything using recursion so I wrote this in Python:

def base10ToBase26Letter(num):
    ''' Converts any positive integer to Base26(letters only) with no 0th 
    case. Useful for applications such as spreadsheet columns to determine which 
    Letterset goes with a positive integer.
    '''
    if num &lt;= 0:
        return ""
    elif num &lt;= 26:
        return chr(96+num)
    else:
        return base10ToBase26Letter(int((num-1)/26))+chr(97+(num-1)%26)

def base26LetterToBase10(string):
    ''' Converts a string from Base26(letters only) with no 0th case to a positive
    integer. Useful for figuring out column numbers from letters so that they can
    be called from a list.
    '''
    string = string.lower()
    if string == " " or len(string) == 0:
        return 0
    if len(string) == 1:
        return ord(string)-96
    else:
        return base26LetterToBase10(string[1:])+(26**(len(string)-1))*(ord(string[0])-96)


I am aware that the first function outputs lowercase letters which can be bypassed by using base10ToBase26Letter(num).upper().

I used this to test the consistency of the values being output:

for x in range(0,100000):
    if x == base26LetterToBase10(base10ToBase26Letter(x)):
        print(x)



Is recursion the best way to approach this problem efficiently, or should I be looking for something else?
If I were to look at readability, is this way the easiest to read?
Does this problem have a shorter solution?
It seems that after about 11 letter digits, this program is no longer accurate, is there a way to make the functions accurate further? (Even if such numbers will never be used in a spreadsheet)
As others already said, recursion doesn't quite fit here. But I’d say it doesn't fit because strings are immutable. In your implementation, you are either concatenating strings or slicing them, which are operations that will produce new strings each time where it shouldn't be necessary.

Instead, iteration is more natural in Python, and you have several builtins that can help you so. The first ones being reversed and enumerate that give you the ability to iterate over each letter in a string in reverse order while knowing the index of the letter: usefull when converting from base alphabet to base 10. And for the base 10 to alphabet conversion, you can extract individual "digits" using divmod and join the generated letters.

Lastly, I’d recommend to stick to the lower_case_with_underscore naming convention for functions as recommended per PEP8.



A_UPPERCASE = ord('A')
ALPHABET_SIZE = 26


def _decompose(number):
    """Generate digits from `number` in base alphabet, least significants
    bits first.

    Since A is 1 rather than 0 in base alphabet, we are dealing with
    `number - 1` at each iteration to be able to extract the proper digits.
    """

    while number:
        number, remainder = divmod(number - 1, ALPHABET_SIZE)
        yield remainder


def base_10_to_alphabet(number):
    """Convert a decimal number to its base alphabet representation"""

    return ''.join(
            chr(A_UPPERCASE + part)
            for part in _decompose(number)
    )[::-1]


def base_alphabet_to_10(letters):
    """Convert an alphabet number to its decimal representation"""

    return sum(
            (ord(letter) - A_UPPERCASE + 1) * ALPHABET_SIZE**i
            for i, letter in enumerate(reversed(letters.upper()))
    )


But, you could use recursion in _decompose in order to not have to reverse the string produced by join:

A_UPPERCASE = ord('A')
ALPHABET_SIZE = 26


def _decompose(number):
    """Generate digits from `number` in base alphabet, most significants
    bits first.
    """

    number -= 1  # Account for A in base alphabet being 1 in decimal rather than 0
    if number &lt; ALPHABET_SIZE:
        yield number
    else:
        number, remainder = divmod(number, ALPHABET_SIZE)
        yield from _decompose(number)
        yield remainder


def base_10_to_alphabet(number):
    """Convert a decimal number to its base alphabet representation"""

    return ''.join(
            chr(A_UPPERCASE + part)
            for part in _decompose(number)
    )


def base_alphabet_to_10(letters):
    """Convert an alphabet number to its decimal representation"""

    return sum(
            (ord(letter) - A_UPPERCASE + 1) * ALPHABET_SIZE**i
            for i, letter in enumerate(reversed(letters.upper()))
    )