Return a list of merged LicenseMatch matches given a `matches` list of LicenseMatch. Merging is a "lossless" operation that combines two or more matches to the same rule and that are in sequence of increasing query and index positions in a single new match.
(matches, max_dist=None, trace=TRACE_MERGE)
| 867 | |
| 868 | |
| 869 | def merge_matches(matches, max_dist=None, trace=TRACE_MERGE): |
| 870 | """ |
| 871 | Return a list of merged LicenseMatch matches given a `matches` list of |
| 872 | LicenseMatch. Merging is a "lossless" operation that combines two or more |
| 873 | matches to the same rule and that are in sequence of increasing query and |
| 874 | index positions in a single new match. |
| 875 | """ |
| 876 | # shortcut for single matches |
| 877 | if len(matches) < 2: |
| 878 | return matches |
| 879 | |
| 880 | # only merge matches with the same rule: sort then group by rule for the |
| 881 | # same rule, sort on start, longer high, longer match, matcher type |
| 882 | sorter = lambda m: (m.rule.identifier, m.qspan.start, -m.hilen(), -m.len(), m.matcher_order) |
| 883 | matches.sort(key=sorter) |
| 884 | matches_by_rule = [ |
| 885 | (rid, list(rule_matches)) |
| 886 | for rid, rule_matches |
| 887 | in groupby(matches, key=lambda m: m.rule.identifier) |
| 888 | ] |
| 889 | |
| 890 | if trace: |
| 891 | print('merge_matches: number of matches to process:', len(matches)) |
| 892 | |
| 893 | if max_dist is None: |
| 894 | max_dist = MAX_DIST |
| 895 | |
| 896 | merged = [] |
| 897 | merged_extend = merged.extend |
| 898 | |
| 899 | for rid, rule_matches in matches_by_rule: |
| 900 | if trace: |
| 901 | logger_debug('merge_matches: processing rule:', rid) |
| 902 | |
| 903 | rule_length = rule_matches[0].rule.length |
| 904 | |
| 905 | # FIXME this is likely too much as we are getting gaps that are often too big |
| 906 | max_rule_side_dist = min((rule_length // 2) or 1, max_dist) |
| 907 | |
| 908 | # compare two matches in the sorted sequence: current and next |
| 909 | i = 0 |
| 910 | while i < len(rule_matches) - 1: |
| 911 | j = i + 1 |
| 912 | while j < len(rule_matches): |
| 913 | current_match = rule_matches[i] |
| 914 | next_match = rule_matches[j] |
| 915 | |
| 916 | if trace: |
| 917 | logger_debug('---> merge_matches: current:', current_match) |
| 918 | logger_debug('---> merge_matches: next: ', next_match) |
| 919 | |
| 920 | # FIXME: also considers the match length! |
| 921 | # stop if we exceed max dist |
| 922 | # or distance over 1/2 of rule length |
| 923 | if (current_match.qdistance_to(next_match) > max_rule_side_dist |
| 924 | or current_match.idistance_to(next_match) > max_rule_side_dist): |
| 925 | |
| 926 | if trace: |