• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

manoss96 / pregex / 4356417821

pending completion
4356417821

push

github

manoss96
add logo and funding

1625 of 1625 relevant lines covered (100.0%)

3.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/pregex/core/groups.py
1
__doc__ = """
3✔
2
This module contains all necessary classes that are used to construct both
3
capturing and non-capturing groups, as well as any other classes which relate
4
to concepts that are based on groups, such as backreferences and conditionals.
5

6
Pattern grouping
7
-------------------------------------------
8
In general, one should not have to concern themselves with pattern grouping,
9
as patterns are automatically wrapped within non-capturing groups whenever this is
10
deemed necessary. Consider for instance the following code snippet:
11

12
.. code-block:: python
13

14
   from pregex.core.quantifiers import Optional
15

16
   Optional('a').print_pattern() # This prints "a?"
17
   Optional('aa').print_pattern() # This prints "(?:aa)?"
18

19
In the first case, quantifier :class:`~pregex.core.quantifiers.Optional` is applied to
20
the pattern directly, whereas in the second case the pattern is placed into a non-capturing
21
group so that "aa" is quantified as a whole. Be that as it may, there exists a separate class,
22
namely :class:`Group`, through which one is able to explicitly wrap any pattern within
23
a non-capturing group if they wish to do so:
24

25
.. code-block:: python
26

27
   from pregex.core.groups import Group
28
   from pregex.core.quantifiers import Optional
29

30
   pre = Group(Optional('a'))
31

32
   pre.print_pattern() # This prints "(?:a)?"
33

34
This class can also be used so as to apply various RegEx flags, also known \
35
as *modifiers*, to a pattern. As of yet, the only flag that is supported is
36
the case-insensitive flag ``i``:
37

38
.. code-block:: python
39

40
   from pregex.core.groups import Group
41

42
   pre = Group('pregex', is_case_insensitive=True)
43

44
   # This statement is "True"
45
   pre.is_exact_match('PRegEx')
46

47

48
Capturing patterns
49
-------------------------------------------
50

51
You'll find however that :class:`Capture` is probably the most important class
52
of this module, as it is used to create a capturing group out of a pattern,
53
so that said pattern is captured separately whenever a match occurs.
54

55
.. code-block:: python
56

57
   from pregex.core.groups import Capture
58
   from pregex.core.classes import AnyLetter
59

60
   pre = AnyLetter() + Capture(2 * AnyLetter())
61

62
   text = "abc def"
63
   print(pre.get_matches(text)) # This prints "['abc', 'def']"
64
   print(pre.get_captures(text)) # This prints "[('bc'), ('ef')]"
65

66
As you can see, capturing is a very useful tool for whenever you are
67
interested in isolating some specific part of a pattern.
68

69
Classes & methods
70
-------------------------------------------
71

72
Below are listed all classes within :py:mod:`pregex.core.groups`
73
along with any possible methods they may possess.
74
"""
75

76

77
import re as _re
3✔
78
import pregex.core.pre as _pre
3✔
79
import pregex.core.exceptions as _ex
3✔
80
from typing import Union as _Union
3✔
81
from typing import Optional as _Optional
3✔
82

83

84
class __Group(_pre.Pregex):
3✔
85
    '''
3✔
86
    Constitutes the base class for all classes that are part of this module.
87

88
    :param Pregex | str pre: A Pregex instance or string representing the pattern \
89
        that is to be groupped.
90
    :param (Pregex => str) transform: A `transform` function for the provided pattern.
91

92
    :raises InvalidArgumentTypeException: Parameter ``pre`` is neither a \
93
        ``Pregex`` instance nor a string.
94
    '''
95
    def __init__(self, pre: _Union[_pre.Pregex, str], transform) -> _pre.Pregex:
3✔
96
        '''
97
        Constitutes the base class for all classes that are part of this module.
98

99
        :param Pregex | str pre: A Pregex instance or string representing the pattern \
100
            that is to be groupped.
101
        :param (Pregex => str) transform: A `transform` function for the provided pattern.
102

103
        :raises InvalidArgumentTypeException: Parameter ``pre`` is neither a \
104
            ``Pregex`` instance nor a string.
105
        '''
106
        pattern = transform(__class__._to_pregex(pre))
3✔
107
        super().__init__(str(pattern), escape=False)
3✔
108

109

110
class Capture(__Group):
3✔
111
    '''
3✔
112
    Creates a capturing group out of the provided pattern.
113

114
    :param Pregex | str pre: The pattern out of which the capturing group is created.
115
    :param str name: The name that is assigned to the captured group \
116
        for backreference purposes. A value of ``None`` indicates that no name \
117
        is to be assigned to the group. Defaults to ``None``.
118

119
    :raises InvalidArgumentTypeException:
120
        - Parameter ``pre`` is neither a ``Pregex`` instance nor a string.
121
        - Parameter ``name`` is neither a string nor ``None``.
122
    :raises InvalidCapturingGroupNameException: Parameter ``name`` is not a valid \
123
        capturing group name. Such name must contain word characters only and start \
124
        with a non-digit character.
125

126
    :note:
127
        - Creating a capturing group out of a capturing group does nothing to it.
128
        - Creating a capturing group out of a non-capturing group converts it \
129
            into a capturing group, except if any flags have been applied to it, \
130
            in which case, the non-capturing group is wrapped within a capturing \
131
            group as a whole.
132
        - Creating a named capturing group out of an unnamed capturing group, \
133
          assigns a name to it.
134
        - Creating a named capturing group out of a named capturing group, \
135
          changes the group's name.
136
    '''
137

138
    def __init__(self, pre: _Union[_pre.Pregex, str], name: _Optional[str] = None):
3✔
139
        '''
140
        Creates a capturing group out of the provided pattern.
141

142
        :param Pregex | str pre: The pattern that is to be wrapped \
143
            within a capturing group.
144
        :param str name: The name that is assigned to the captured group \
145
            for backreference purposes. A value of ``None`` indicates that no name \
146
            is to be assigned to the group. Defaults to ``None``.
147

148
        :raises InvalidArgumentTypeException:
149
            - Parameter ``pre`` is neither a ``Pregex`` instance nor a string.
150
            - Parameter ``name`` is neither a string nor ``None``.
151
        :raises InvalidCapturingGroupNameException: Parameter ``name`` is not a valid \
152
            capturing group name. Such name must contain word characters only and start \
153
            with a non-digit character.
154

155
        :note:
156
            - Creating a capturing group out of a capturing group does nothing to.
157
            - Creating a capturing group out of a non-capturing group converts it \
158
              into a capturing group, except if any flags have been applied to it, \
159
              in which case, the non-capturing group is wrapped within a capturing \
160
              group as a whole.
161
            - Creating a named capturing group out of an unnamed capturing group, \
162
              assigns a name to it.
163
            - Creating a named capturing group out of a named capturing group, \
164
              changes the group's name.
165
        '''
166
        super().__init__(pre, lambda pre: pre.capture(name))
3✔
167

168

169
class Group(__Group):
3✔
170
    '''
3✔
171
    Creates a non-capturing group out of the provided pattern.
172

173
    :param Pregex | str pre: The pattern that is to be wrapped \
174
        within a non-capturing group.
175
    :param bool is_case_insensitive: If ``True``, then the "case insensitive" \
176
        flag is applied to the group so that the pattern within it ignores case \
177
        when it comes to matching. Defaults to ``False``.
178

179
    :raises InvalidArgumentTypeException: Parameter ``pre`` is neither \
180
        a ``Pregex`` instance nor a string.
181

182
    :note:
183
        - Creating a non-capturing group out of a non-capturing group does nothing, \
184
          except for remove its flags if it has any.
185
        - Creating a non-capturing group out of a capturing group converts it into \
186
          a non-capturing group.
187
    '''
188

189
    def __init__(self, pre: _Union[_pre.Pregex, str], is_case_insensitive: bool = False):
3✔
190
        '''
191
        Creates a non-capturing group out of the provided pattern.
192

193
        :param Pregex | str pre: The pattern that is to be wrapped \
194
            within a non-capturing group.
195
        :param bool is_case_insensitive: If ``True``, then the "case insensitive" \
196
            flag is applied to the group so that the pattern within it ignores case \
197
            when it comes to matching. Defaults to ``False``.
198

199
        :raises InvalidArgumentTypeException: Parameter ``pre`` is neither \
200
            a ``Pregex`` instance nor a string.
201

202
        :note:
203
            - Creating a non-capturing group out of a non-capturing group does nothing, \
204
              except for remove its flags if it has any.
205
            - Creating a non-capturing group out of a capturing group converts it into \
206
            a non-capturing group.
207
        '''
208
        super().__init__(pre, lambda pre: pre.group(is_case_insensitive))
3✔
209

210

211
class Backreference(__Group):
3✔
212
    '''
3✔
213
    Creates a backreference to some previously declared capturing group.
214

215
    :param int | str ref: A reference to some previously declared capturing group. \
216
        This parameter can either be an integer, in which case the capturing group \
217
        is referenced by order, or a string, in which case the capturing group is \
218
        referenced by name.
219

220
    :raises InvalidArgumentTypeException: Parameter ``ref`` is neither an integer \
221
        nor a string.
222
    :raises InvalidArgumentValueException: Parameter ``ref`` is an integer but \
223
        has a value of either less than ``1`` or greater than ``10``.
224
    :raises InvalidCapturingGroupNameException: Parameter ``ref`` is a string but \
225
        not a valid capturing group name. Such name must contain word characters \
226
        only and start with a non-digit character.
227
    '''
228

229
    def __init__(self, ref: _Union[int, str]):
3✔
230
        '''
231
        Creates a backreference to some previously declared capturing group.
232

233
        :param int | str ref: A reference to some previously declared capturing group. \
234
            This parameter can either be an integer, in which case the capturing group \
235
            is referenced by order, or a string, in which case the capturing group is \
236
            referenced by name.
237

238
        :raises InvalidArgumentTypeException: Parameter ``ref`` is neither an integer \
239
            nor a string.
240
        :raises InvalidArgumentValueException: Parameter ``ref`` is an integer but \
241
            has a value of either less than ``1`` or greater than ``10``.
242
        :raises InvalidCapturingGroupNameException: Parameter ``ref`` is a string but \
243
            not a valid capturing group name. Such name must contain word characters \
244
            only and start with a non-digit character.
245
        '''
246
        if isinstance(ref, int):
3✔
247
            if isinstance(ref, bool):
3✔
248
                message = "Parameter \"ref\" is neither an integer nor a string."
3✔
249
                raise _ex.InvalidArgumentTypeException(message)
3✔
250
            if ref < 1 or ref > 99:
3✔
251
                message = "Parameter \"ref\" cannot be less than 1 or greater than 99."
3✔
252
                raise _ex.InvalidArgumentValueException(message)
3✔
253
            transform = lambda s : f"\\{s}"
3✔
254
        elif isinstance(ref, str):
3✔
255
            if _re.fullmatch("[A-Za-z_][A-Za-z_0-9]*", ref) is None:
3✔
256
                raise _ex.InvalidCapturingGroupNameException(ref)
3✔
257
            transform = lambda s : f"(?P={s})"
3✔
258
        else:
259
            message = "Parameter \"ref\" is neither an integer nor a string."
3✔
260
            raise _ex.InvalidArgumentTypeException(message)
3✔
261
        super().__init__(str(ref), transform)
3✔
262

263
    
264
class Conditional(__Group):
3✔
265
    '''
3✔
266
    Given the name of a capturing group, matches ``pre1`` only if said capturing group has \
267
    been previously matched. Furthermore, if a second pattern ``pre2`` is provided, then \
268
    this pattern is matched in case the referenced capturing group was not, though one \
269
    should be aware that for this to be possible, the referenced capturing group must \
270
    be optional.
271

272
    :param str name: The name of the referenced capturing group.
273
    :param Pregex | str pre1: The pattern that is to be matched in case condition is true.
274
    :param Pregex | str pre2: The pattern that is to be matched in case condition \
275
        is false. Defaults to ``None``.
276

277
    :raises InvalidArgumentTypeException:
278
        - Parameter ``name`` is not a string.
279
        - Parameter ``pre1`` is neither a ``Pregex`` instance nor a string.
280
        - Parameter ``pre2`` is neither a ``Pregex`` instance nor a string nor ``None``.
281
    :raises InvalidCapturingGroupNameException: Parameter ``name`` is not a valid \
282
        capturing group name. Such name must contain word characters only and start \
283
        with a non-digit character.
284
    '''
285

286
    def __init__(self, name: str, pre1: _Union[_pre.Pregex, str], pre2: _Optional[_Union[_pre.Pregex, str]] = None):
3✔
287
        '''
288
        Given the name of a capturing group, matches ``pre1`` only if said capturing group has \
289
        been previously matched. Furthermore, if a second pattern ``pre2`` is provided, then \
290
        this pattern is matched in case the referenced capturing group was not, though one \
291
        should be aware that for this to be possible, the referenced capturing group must \
292
        be optional.
293

294
        :param str name: The name of the referenced capturing group.
295
        :param Pregex | str pre1: The pattern that is to be matched in case condition is true.
296
        :param Pregex | str pre2: The pattern that is to be matched in case condition \
297
            is false. Defaults to ``None``.
298

299
        :raises InvalidArgumentTypeException:
300
            - Parameter ``name`` is not a string.
301
            - Parameter ``pre1`` is neither a ``Pregex`` instance nor a string.
302
            - Parameter ``pre2`` is neither a ``Pregex`` instance nor a string nor ``None``.
303
        :raises InvalidCapturingGroupNameException: Parameter ``name`` is not a valid \
304
            capturing group name. Such name must contain word characters only and start \
305
            with a non-digit character.
306
        '''
307
        if not isinstance(name, str):
3✔
308
            message = "Provided argument \"name\" is not a string."
3✔
309
            raise _ex.InvalidArgumentTypeException(message)
3✔
310
        if _re.fullmatch("[A-Za-z_][\w]*", name) is None:
3✔
311
            raise _ex.InvalidCapturingGroupNameException(name)
3✔
312
        super().__init__(name, lambda s: f"(?({s}){pre1}{'|' + str(pre2) if pre2 != None else ''})")
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc