Try the following:
(?<=\d)(?=(\d{2}){0,2}\d{3}(\d{7})*(?!\d))
For example:
>>> import re >>> inp = ["1" + "0"*i for i in range(20)] >>> [re.sub(r"(?<=\d)(?=(\d{2}){0,2}\d{3}(\d{7})*(?!\d))", ",", i) for i in inp] ['1', '10', '100', '1,000', '10,000', '1,00,000', '10,00,000', '1,00,00,000', '10,00,00,000', '100,00,00,000', '1,000,00,00,000', '10,000,00,00,000', '1,00,000,00,00,000', '10,00,000,00,00,000', '1,00,00,000,00,00,000', '10,00,00,000,00,00,000', '100,00,00,000,00,00,000', '1,000,00,00,000,00,00,000', '10,000,00,00,000,00,00,000', '1,00,000,00,00,000,00,00,000']
As a commented regular expression:
result = re.sub( r"""(?x) # Enable verbose mode (comments) (?<=\d) # Assert that we're not at the start of the number. (?= # Assert that it possible to match: (\d{2}){0,2} # 0, 2 or 4 digits, \d{3} # followed by 3 digits, (\d{7})* # followed by 0, 7, 14, 21 ... digits, (?!\d) # and no more digits after that. ) # End of lookahead assertion.""", ",", subject)