| 735 | # \throws ValueError |
| 736 | # Thrown if the format string does not conform to standards |
| 737 | def splitAndParseTypesInFmtString(fmtString): |
| 738 | # This function follows the standard according to the cplusplus reference |
| 739 | # http://www.cplusplus.com/reference/cstdio/printf/ (9/7/16) |
| 740 | |
| 741 | # These are the set of characters that can serve as specifiers |
| 742 | signedSet = 'di' |
| 743 | unsignedSet = 'uoxX' |
| 744 | floatSet = 'fFeEgGaA' |
| 745 | integerSet = signedSet + unsignedSet |
| 746 | |
| 747 | # The next while loop scans through the string looking for unescaped "%" |
| 748 | matches = [] |
| 749 | charIndex = 0 |
| 750 | consecutivePercents = 0 |
| 751 | startOfNextSpecifierSubstring = 0 |
| 752 | while charIndex < len(fmtString): |
| 753 | c = fmtString[charIndex] |
| 754 | |
| 755 | if c == "\\": |
| 756 | # Skip the next character if there's an escape |
| 757 | charIndex += 1 |
| 758 | elif c == "%": |
| 759 | consecutivePercents += 1 |
| 760 | if consecutivePercents % 2 == 1: |
| 761 | # At this point we should be at a %, so try to regex it |
| 762 | match = re.match("^%" |
| 763 | "(?P<flags>[-+ #0]+)?" |
| 764 | "(?P<width>[\\d]+|\\*)?" |
| 765 | "(\\.(?P<precision>\\d+|\\*))?" |
| 766 | "(?P<length>hh|h|l|ll|j|z|Z|t|L)?" |
| 767 | "(?P<specifier>[diuoxXfFeEgGaAcspn])", |
| 768 | fmtString[charIndex:]) |
| 769 | |
| 770 | if match: |
| 771 | endPos = charIndex + len(match.group(0)) |
| 772 | substring = fmtString[startOfNextSpecifierSubstring:endPos] |
| 773 | startOfNextSpecifierSubstring = endPos |
| 774 | |
| 775 | matches.append((match, substring)) |
| 776 | elif not re.match("%%", fmtString[charIndex:]): |
| 777 | raise ValueError("Unrecognized Format Specifier: \"%s\"" % |
| 778 | fmtString[charIndex:].split()[0]) |
| 779 | else: |
| 780 | consecutivePercents = 0 |
| 781 | |
| 782 | charIndex += 1 |
| 783 | |
| 784 | # Fold in the remainder of the format string into the last argument if it |
| 785 | # exists; otherwise just return our format-less string |
| 786 | if len(matches) > 0: |
| 787 | lastItem = matches.pop() |
| 788 | matches.append((lastItem[0], |
| 789 | lastItem[1] + fmtString[startOfNextSpecifierSubstring:])) |
| 790 | else: |
| 791 | return [FmtType(None, None, None, fmtString)] |
| 792 | |
| 793 | types = [] |
| 794 | for (fmt, substring) in matches: |