def string_stats(strs, valid_chars='<STR_LIT>', left_pad='<STR_LIT:0>', right_pad='<STR_LIT>', strip=True):
if left_pad is None:<EOL><INDENT>left_pad = '<STR_LIT>'.join(c for c in rex.ASCII_CHARACTERS if c not in valid_chars)<EOL><DEDENT>if right_pad is None:<EOL><INDENT>right_pad = '<STR_LIT>'.join(c for c in rex.ASCII_CHARACTERS if c not in valid_chars)<EOL><DEDENT>def normalize(s):<EOL><INDENT>if strip:<EOL><INDENT>s = s.strip()<EOL><DEDENT>s = s.lstrip(left_pad)<EOL>s = s.rstrip(right_pad)<EOL>return s<EOL><DEDENT>strs = [normalize(s) for s in strs]<EOL>lengths = Counter(len(s) for s in strs)<EOL>counts = {}<EOL>max_length = max(lengths.keys())<EOL>for i in range(max_length):<EOL><INDENT>for s in strs:<EOL><INDENT>if i < len(s):<EOL><INDENT>counts[i] = counts.get(i, <NUM_LIT:0>) + int(s[i] in valid_chars)<EOL>counts[-i - <NUM_LIT:1>] = counts.get(-i - <NUM_LIT:1>, <NUM_LIT:0>) + int(s[-i - <NUM_LIT:1>] in valid_chars)<EOL><DEDENT><DEDENT>long_enough_strings = float(sum(c for n, c in list(lengths.items()) if n >= i))<EOL>counts[i] = counts[i] / long_enough_strings<EOL>counts[-i - <NUM_LIT:1>] = counts[-i - <NUM_LIT:1>] / long_enough_strings<EOL><DEDENT>return counts<EOL>
Count the occurrence of a category of valid characters within an iterable of serial/model no, etc