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))
def anything(text):
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.

def check_parse_format(format, 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)