1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>. 4 5""" 6Regular expression ancillary classes. 7 8Those help caching regular expressions and do matching for kernel-doc. 9""" 10 11import re 12 13# Local cache for regular expressions 14re_cache = {} 15 16 17class KernRe: 18 """ 19 Helper class to simplify regex declaration and usage. 20 21 It calls re.compile for a given pattern. It also allows adding 22 regular expressions and define sub at class init time. 23 24 Regular expressions can be cached via an argument, helping to speedup 25 searches. 26 """ 27 28 def _add_regex(self, string, flags): 29 """ 30 Adds a new regex or reuses it from the cache. 31 """ 32 self.regex = re_cache.get(string, None) 33 if not self.regex: 34 self.regex = re.compile(string, flags=flags) 35 if self.cache: 36 re_cache[string] = self.regex 37 38 def __init__(self, string, cache=True, flags=0): 39 """ 40 Compile a regular expression and initialize internal vars. 41 """ 42 43 self.cache = cache 44 self.last_match = None 45 46 self._add_regex(string, flags) 47 48 def __str__(self): 49 """ 50 Return the regular expression pattern. 51 """ 52 return self.regex.pattern 53 54 def __repr__(self): 55 """ 56 Returns a displayable version of the class init. 57 """ 58 59 flag_map = { 60 re.IGNORECASE: "re.I", 61 re.MULTILINE: "re.M", 62 re.DOTALL: "re.S", 63 re.VERBOSE: "re.X", 64 } 65 66 flags = [] 67 for flag, name in flag_map.items(): 68 if self.regex.flags & flag: 69 flags.append(name) 70 71 flags_name = " | ".join(flags) 72 73 max_len = 60 74 pattern = "" 75 for pos in range(0, len(self.regex.pattern), max_len): 76 pattern += '"' + self.regex.pattern[pos:max_len + pos] + '" ' 77 78 if flags_name: 79 return f'KernRe({pattern}, {flags_name})' 80 else: 81 return f'KernRe({pattern})' 82 83 def __add__(self, other): 84 """ 85 Allows adding two regular expressions into one. 86 """ 87 88 return KernRe(str(self) + str(other), cache=self.cache or other.cache, 89 flags=self.regex.flags | other.regex.flags) 90 91 def match(self, string): 92 """ 93 Handles a re.match storing its results. 94 """ 95 96 self.last_match = self.regex.match(string) 97 return self.last_match 98 99 def search(self, string): 100 """ 101 Handles a re.search storing its results. 102 """ 103 104 self.last_match = self.regex.search(string) 105 return self.last_match 106 107 def finditer(self, string): 108 """ 109 Alias to re.finditer. 110 """ 111 112 return self.regex.finditer(string) 113 114 def findall(self, string): 115 """ 116 Alias to re.findall. 117 """ 118 119 return self.regex.findall(string) 120 121 def split(self, string): 122 """ 123 Alias to re.split. 124 """ 125 126 return self.regex.split(string) 127 128 def sub(self, sub, string, count=0): 129 """ 130 Alias to re.sub. 131 """ 132 133 return self.regex.sub(sub, string, count=count) 134 135 def group(self, num): 136 """ 137 Returns the group results of the last match. 138 """ 139 140 return self.last_match.group(num) 141 142 def groups(self): 143 """ 144 Returns the group results of the last match 145 """ 146 147 return self.last_match.groups() 148