openrvdas.logger.utils.check_parse_format
Check whether a PyPi parse string format matches a given string. If not, show at what point the match fails.
logger/utils/check_parse_format.py --format '$GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat},{EorW:w}' --string '$GPGLL,2203.672,S,01759.539,W'
Matches!
logger/utils/check_parse_format.py --format '$GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat},{EorW:w}' --string '$GPGLL,2203.672,S,01759.5x39,W'
Matches up to $GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat} $GPGLL,2203.672,S,01759.5x39,W _________________________^
NOTE: When used from the command line, unless you use single (not double) quotes on your strings, any "$" character will be interpreted as the start of a shell variable and may muck up your match.
1#!/usr/bin/env python3 2"""Check whether a PyPi parse string format matches a given string. If 3not, show at what point the match fails. 4 5 > logger/utils/check_parse_format.py \ 6 --format '$GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat},{EorW:w}' \ 7 --string '$GPGLL,2203.672,S,01759.539,W' 8 9 Matches! 10 11 > logger/utils/check_parse_format.py \ 12 --format '$GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat},{EorW:w}' \ 13 --string '$GPGLL,2203.672,S,01759.5x39,W' 14 15 Matches up to $GPGLL,{Latitude:nlat},{NorS:w},{Longitude:nlat} 16 $GPGLL,2203.672,S,01759.5x39,W 17 _________________________^ 18 19***NOTE***: When used from the command line, unless you use single (not 20double) quotes on your strings, any "$" character will be interpreted 21as the start of a shell variable and may muck up your match. 22 23""" 24import parse 25import pprint 26 27# Append openrvdas root to syspath prior to importing openrvdas modules 28 29# Dict of format types that extend the default formats recognized by the 30# parse module. 31from logger.utils.record_parser_formats import extra_format_types # noqa: E402 32 33# We add an "anything" type to eat up stuff at the end of a string 34 35 36def anything(text): 37 """Method for parsing a string (or anything) between commas 38 string.""" 39 if text: 40 return text 41 else: 42 return None 43 44 45anything.pattern = r'.*' 46 47extra_format_types['anything'] = anything 48 49 50################################################################################ 51def check_parse_format(format, string): 52 """Check whether a format pattern matches a string. If there is a 53 complete match, return 54 55 (match_dict, None, None) 56 57 If there is a partial match, return 58 59 (match_dict, index_of_max_match, substring of pattern that matches) 60 61 If there is no match, return 62 63 (None, None, None) 64 """ 65 66 # First check: do we match the entire string? If so, we're done - 67 # return None. 68 p = parse.parse(format, string, extra_types=extra_format_types) 69 if p: 70 return (p.named, None, None) 71 72 # If we haven't matched, try matching shorter and shorter patterns, 73 # followed by anything. 74 max_index = len(format) 75 while max_index > 0: 76 new_format = format[0:max_index] + '{Anything:anything}' 77 try: 78 p = parse.parse(new_format, string, extra_types=extra_format_types) 79 except ValueError: # Probably got an incomplete pattern. Keep chopping. 80 p = None 81 82 if p: 83 del p.spans['Anything'] 84 del p.named['Anything'] 85 span_ends = [v[1] for k, v in p.spans.items()] or [0] 86 max_span = max(span_ends) 87 return (p.named, max_span, format[0:max_index]) 88 89 # If didn't match, shorten the format 90 # print('Didn\'t match "{}"'.format(format[0:max_index])) 91 max_index -= 1 92 93 # Nothing ever matched 94 return (None, None, None) 95 96 97################################################################################ 98if __name__ == '__main__': 99 import argparse 100 parser = argparse.ArgumentParser() 101 102 parser.add_argument('--format', dest='format', help='PyPi format string') 103 parser.add_argument('--string', dest='string', help='String to match') 104 args = parser.parse_args() 105 106 match_dict, max_span, format = check_parse_format(args.format, args.string) 107 print('') 108 if match_dict is None: 109 print('No match at all!') 110 elif max_span is None: 111 print('Matches: %s' % pprint.pformat(match_dict)) 112 else: 113 print('Partial match up to "{}"'.format(format)) 114 print(args.string) 115 print('_' * max_span + '^') 116 print('Values: %s' % pprint.pformat(match_dict))
37def anything(text): 38 """Method for parsing a string (or anything) between commas 39 string.""" 40 if text: 41 return text 42 else: 43 return None
Method for parsing a string (or anything) between commas string.
52def check_parse_format(format, string): 53 """Check whether a format pattern matches a string. If there is a 54 complete match, return 55 56 (match_dict, None, None) 57 58 If there is a partial match, return 59 60 (match_dict, index_of_max_match, substring of pattern that matches) 61 62 If there is no match, return 63 64 (None, None, None) 65 """ 66 67 # First check: do we match the entire string? If so, we're done - 68 # return None. 69 p = parse.parse(format, string, extra_types=extra_format_types) 70 if p: 71 return (p.named, None, None) 72 73 # If we haven't matched, try matching shorter and shorter patterns, 74 # followed by anything. 75 max_index = len(format) 76 while max_index > 0: 77 new_format = format[0:max_index] + '{Anything:anything}' 78 try: 79 p = parse.parse(new_format, string, extra_types=extra_format_types) 80 except ValueError: # Probably got an incomplete pattern. Keep chopping. 81 p = None 82 83 if p: 84 del p.spans['Anything'] 85 del p.named['Anything'] 86 span_ends = [v[1] for k, v in p.spans.items()] or [0] 87 max_span = max(span_ends) 88 return (p.named, max_span, format[0:max_index]) 89 90 # If didn't match, shorten the format 91 # print('Didn\'t match "{}"'.format(format[0:max_index])) 92 max_index -= 1 93 94 # Nothing ever matched 95 return (None, None, None)
Check whether a format pattern matches a string. If there is a complete match, return
(match_dict, None, None)
If there is a partial match, return
(match_dict, index_of_max_match, substring of pattern that matches)
If there is no match, return
(None, None, None)