Source code for pregex.meta.essentials

__doc__ = '''
This module contains various classes that can be used to match
all sorts of commonly-search-for patterns.

Classes & methods
-------------------------------------------

Below are listed all classes within :py:mod:`pregex.meta.essentials`
along with any possible methods they may possess.
'''

import pregex.core.pre as _pre
import pregex.core.groups as _gr
import pregex.core.classes as _cl
import pregex.core.operators as _op
import pregex.core.exceptions as _ex
import pregex.core.assertions as _asr
import pregex.core.quantifiers as _qu
from typing import Union as _Union
from typing import Optional as _Optional


[docs]class Text(_pre.Pregex): ''' Matches any string of text of arbitrary length. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' def __init__(self, is_optional: bool = False) -> _pre.Pregex: ''' Matches any string of text of arbitrary length. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' if is_optional: pre = _qu.Indefinite(_cl.Any()) else: pre = _qu.OneOrMore(_cl.Any()) super().__init__(str(pre), escape=False)
[docs]class NonWhitespace(_pre.Pregex): ''' Matches any string of text of arbitrary length that does not contain \ any whitespace characters. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' def __init__(self, is_optional: bool = False) -> _pre.Pregex: ''' Matches any string of text of arbitrary length that does not contain \ any whitespace characters. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' if is_optional: pre = _qu.Indefinite(_cl.AnyButWhitespace()) else: pre = _qu.OneOrMore(_cl.AnyButWhitespace()) super().__init__(str(pre), escape=False)
[docs]class Whitespace(_pre.Pregex): ''' Matches any string of whitespace characters of arbitrary length. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' def __init__(self, is_optional: bool = False) -> _pre.Pregex: ''' Matches any string of whitespace characters of arbitrary length. :param bool is_optional: Determines whether this pattern is optional \ or not. Defaults to ``False``. ''' if is_optional: pre = _qu.Indefinite(_cl.AnyWhitespace()) else: pre = _qu.OneOrMore(_cl.AnyWhitespace()) super().__init__(str(pre), escape=False)
class __Word(_pre.Pregex): ''' This is the base class for every "Word" as well as the "Numeral" class. :param Pregex pre: A Pregex instance representing the word pattern. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. ''' def __init__(self, pre: _pre.Pregex, is_extensible: bool) -> _pre.Pregex: ''' This is the base class for every "Word" class. :param Pregex pre: A Pregex instance representing the word pattern. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. ''' if not is_extensible: pre = pre.enclose(_asr.WordBoundary()) super().__init__(str(pre), escape=False)
[docs]class Word(__Word): ''' Matches any word. :param int min_chars: The minimum amount of characters a word must have in order to \ be considered a match. Defaults to ``1``. :param int max_chars: The maximum amount of characters a word must have in order to \ be considered a match. If set to "None", then it is considered that there is no upper limit to the amount of characters a word can have. Defaults to ``None``. :param is_global: Determines whether to include foreign characters. Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: - Parameter ``min_chars`` is not an integer. - Parameter ``max_chars`` is neither an integer nor ``None``. :raises InvalidArgumentValueException: - Either parameter ``min_chars`` or ``max_chars`` has a value of less than ``1``. - Parameter ``min_chars`` has a greater value than that of parameter ``max_chars``. ''' def __init__(self, min_chars: int = 1, max_chars: _Optional[int] = None, is_global: bool = True, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any word. :param int min_chars: The minimum amount of characters a word must have in order to \ be considered a match. Defaults to ``1``. :param int max_chars: The maximum amount of characters a word must have in order to \ be considered a match. If set to "None", then it is considered that there is no upper limit to the amount of characters a word can have. Defaults to ``None``. :param is_global: Determines whether to include foreign characters. Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: - Parameter ``min_chars`` is not an integer. - Parameter ``max_chars`` is neither an integer nor ``None``. :raises InvalidArgumentValueException: - Either parameter ``min_chars`` or ``max_chars`` has a value of less than ``1``. - Parameter ``min_chars`` has a greater value than that of parameter ``max_chars``. ''' pre = _cl.AnyWordChar(is_global=is_global) if not isinstance(min_chars, int): message = "Provided argument \"min_chars\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif min_chars < 1: message = "The value of parameter \"min_chars\" must be greater than zero." raise _ex.InvalidArgumentValueException(message) elif not isinstance(max_chars, int): if max_chars is not None: message = "Provided argument \"max_chars\" must be either an integer nor \"None\"." raise _ex.InvalidArgumentTypeException(message) elif max_chars < 1: message = "The value of parameter \"max_chars\" must be greater than zero." raise _ex.InvalidArgumentValueException(message) elif min_chars > max_chars: message = "The value of parameter \"max\" must be" message += " greater than the value of parameter \"min\"." raise _ex.InvalidArgumentValueException(message) pre = pre.at_least_at_most(n=min_chars, m=max_chars) super().__init__(pre, is_extensible)
[docs]class WordContains(__Word): ''' Matches any word that contains either one of the provided strings. :param str | list[str] infix: Either a string or a list of strings at \ least one of which a word must contain in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided infixes is not a string. ''' def __init__(self, infix: _Union[str, list[str]], is_global: bool = True, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any word that contains either one of the provided strings. :param str | list[str] infix: Either a string or a list of strings at \ least one of which a word must contain in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided infixes is not a string. ''' if not isinstance(infix, list): infix = [infix] for s in infix: if not isinstance(s, str): message = f"Provided infix argument \"{s}\" is not a string." raise _ex.InvalidArgumentTypeException(message) pre = _op.Enclose( _op.Either(*infix), _qu.Indefinite(_cl.AnyWordChar(is_global=is_global)) ) super().__init__(pre, is_extensible)
[docs]class WordStartsWith(__Word): ''' Matches any word that starts with either one of the provided strings. :param str | list[str] prefix: Either a string or a list of strings with \ any of which a word must start in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided prefixes is not a string. ''' def __init__(self, prefix: _Union[str, list[str]], is_global: bool = True, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any word that starts with either one of the provided strings. :param str | list[str] prefix: Either a string or a list of strings with \ any of which a word must start in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided prefixes is not a string. ''' if not isinstance(prefix, list): prefix = [prefix] for s in prefix: if not isinstance(s, str): message = f"Provided prefix argument \"{s}\" is not a string." raise _ex.InvalidArgumentTypeException(message) pre = _op.Either(*prefix) pre = pre + _qu.Indefinite(_cl.AnyWordChar(is_global=is_global)) super().__init__(pre, is_extensible)
[docs]class WordEndsWith(__Word): ''' Matches any word that ends with either one of the provided strings. :param str | list[str] suffix: Either a string or a list of strings with \ any of which a word must end in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided suffixes is not a string. ''' def __init__(self, suffix: _Union[str, list[str]], is_global: bool = True, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any word that ends with either one of the provided strings. :param str | list[str] suffix: Either a string or a list of strings with \ any of which a word must end in order to be considered a match. :param is_global: Determines whether to include foreign characters. \ Defaults to ``True``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: At least one of the provided suffixes is not a string. ''' if not isinstance(suffix, list): suffix = [suffix] for s in suffix: if not isinstance(s, str): message = f"Provided suffix argument \"{s}\" is not a string." raise _ex.InvalidArgumentTypeException(message) pre = _op.Either(*suffix) pre = _qu.Indefinite(_cl.AnyWordChar(is_global=is_global)) + pre super().__init__(pre, is_extensible)
[docs]class Numeral(__Word): ''' Matches any numeral. :param int base: An integer through which the numeral system is specified. \ Defaults to ``10``. :param int n_min: The minimum amount of digits the number may contain. \ Defaults to ``1``. :param int n_max: The maximum amount of digits the number may contain. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: - Parameter ``base`` or ``n_min`` is not an integer. - Parameter ``n_max`` is neither an integer nor ``None``. :raises InvalidArgumentValueException: - Parameter ``base`` has a value of less than ``2`` or greater than ``16``. - Either parameter ``n_min`` or ``n_max`` has a value of less than zero. - Parameter ``n_min`` has a greater value than that of parameter ``n_max``. :note: Setting ``n_max`` equal to ``None`` indicates that there is no upper limit to \ the number of digits. ''' def __init__(self, base: int = 10, n_min: int = 1, n_max: _Optional[int] = None, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any numeral. :param int base: An integer through which the numeral system is specified. \ Defaults to ``10``. :param int n_min: The minimum amount of digits the number may contain. \ Defaults to ``1``. :param int n_max: The maximum amount of digits the number may contain. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: - Parameter ``base`` or ``n_min`` is not an integer. - Parameter ``n_max`` is neither an integer nor ``None``. :raises InvalidArgumentValueException: - Parameter ``base`` has a value of less than ``2`` or greater than ``16``. - Either parameter ``n_min`` or ``n_max`` has a value of less than zero. - Parameter ``n_min`` has a greater value than that of parameter ``n_max``. :note: Setting ``n_max`` equal to ``None`` indicates that there is no upper limit to \ the number of digits. ''' if not isinstance(base, int): message = "Provided argument \"base\" must be an integer." raise _ex.InvalidArgumentTypeException(message) if base < 2 or base > 16: message = "Provided argument \"base\" must be between ``2`` and ``16``." raise _ex.InvalidArgumentValueException(message) if not isinstance(n_min, int) or isinstance(n_min, bool): message = "Provided argument \"n_min\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif n_min < 0: message = "Parameter \"n_min\" must be positive." raise _ex.InvalidArgumentValueException(message) elif not isinstance(n_max, int) or isinstance(n_max, bool): if n_max is not None: message = "Provided argument \"n_max\" must be either an integer or \"None\"." raise _ex.InvalidArgumentTypeException(message) elif n_max < 0: message = "Parameter \"n_max\" must be positive." raise _ex.InvalidArgumentValueException(message) elif n_max < n_min: message = "The value of parameter \"n_max\" must be" message += " greater than the value of parameter \"n_min\"." raise _ex.InvalidArgumentValueException(message) if base == 2: pre = _op.Either("0", "1") else: pre = _cl.AnyBetween("0", "1") digit_map = {i : str(i-1) for i in range(11)} | \ {11 : _cl.AnyFrom("a", "A"), 12 : _cl.AnyFrom("b", "B"), 13 : _cl.AnyFrom("c", "C"), 14 : _cl.AnyFrom("d", "D"), 15 : _cl.AnyFrom("e", "E"), 16 : _cl.AnyFrom("f", "F")} for i in range(2, base + 1): pre = pre | digit_map[i] pre = pre.at_least_at_most(n=n_min, m=n_max) super().__init__(pre, is_extensible)
class __Integer(_pre.Pregex): ''' Every "Integer" class inherits from this class. :param Pregex sign: A "Pregex" instance that is to be concatenated \ to the left of the integer. :param int start: The starting value of the range. :param int end: The ending value of the range. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. ''' def __init__(self, sign: _pre.Pregex, start: int, end: int, is_extensible: bool) -> _pre.Pregex: ''' Every "Integer" class inherits from this class. :param Pregex sign: A "Pregex" instance that is to be concatenated \ to the left of the integer. :param int start: The starting value of the range. :param int end: The ending value of the range. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. ''' if not isinstance(start, int): message = "Provided argument \"start\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif not isinstance(end, int): message = "Provided argument \"end\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif start < 0: message = "Parameter \"start\" must be positive." raise _ex.InvalidArgumentValueException(message) if start > end: message = "Parameter \"end\" must have a greater value than parameter \"start\"." raise _ex.InvalidArgumentValueException(message) pre = sign + __class__.__integer(start, end, is_extensible) super().__init__(str(pre), escape=False) def __integer(start: int, end: int, is_extensible: bool) -> _pre.Pregex: ''' Returns a ``Pregex`` instance able to match integers \ within the specified range. :param int start: The starting value of the range. :param int end: The ending value of the range. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. ''' # Used to fill-in empty space in "start" string. filler = "F" def any_between(d_start: str, d_end: str, is_first: bool = False) -> _pre.Pregex: ''' Performs some checks and modifications before \ returing the specified range class. :param str d_start: The start of the range. :param str d_end: The end of the range. :param bool is_first: Indicates whether this function is \ called during the first iteration. Defaults to ``False``. ''' if d_start == filler: d_start = '1' if is_first else '0' if d_start == d_end: return _pre.Pregex(d_start) return _cl.AnyBetween(d_start, d_end) start, end = str(start), str(end) start = f"{filler * (len(end) - len(start))}{start}" integer_start = _pre.Pregex().preceded_by(_cl.AnyButDigit()) \ if is_extensible else _asr.WordBoundary() p_start = integer_start p_end = integer_start pre = integer_start for i, (d_start, d_end) in enumerate(zip(start, end)): # "if" block will always execute for i == 0. if str(p_start) == str(p_end): digit_pre = any_between(d_start, d_end, i==0) else: digit_pre = _op.Either( any_between(d_start, '9').preceded_by(p_start), any_between('0', d_end).preceded_by(p_end), _asr.NotPrecededBy( _cl.AnyDigit(), *[p for p in (p_start, p_end) if p._get_type() != _pre._Type.Empty] ) ) if i > 1: digit_pre = \ _asr.NotPrecededBy( digit_pre, *[_cl.AnyButDigit() + '0' + (i - 2) * _cl.AnyDigit() for i in range(2, i+1)] ) p_start += d_start.replace(filler, '') p_end += d_end if d_start == filler: digit_pre = _qu.Optional(digit_pre) pre += digit_pre if not is_extensible: pre += _asr.WordBoundary() return pre
[docs]class Integer(__Integer): ''' Matches any integer within a specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool include_sign: Determines whether to include any existing \ signs into the match, or just ignore them. Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: - Be aware that parameter ``include_sign`` might not only play a role in \ deciding the content of the matches, but their number as well. For example, \ setting ``include_sign`` to ``False`` will result in ``Integer`` matching both \ ``1`` and ``2`` in ``1+2``, whereas setting it to ``True`` results in just \ matching ``1``. That is, because in case ``include_sign`` is ``True``, ``+2`` \ is considered an integer as a whole, and as such, it cannot match when another \ digit, namely ``1``, directly precedes it. - Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in \ such a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, include_sign: bool = False, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any integer within the specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool include_sign: Determines whether to include any existing \ signs into the match, or just ignore them. Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: - Be aware that parameter ``include_sign`` might not only play a role in \ deciding the content of the matches, but their number as well. For example, \ setting ``include_sign`` to ``False`` will result in ``Integer`` matching both \ ``1`` and ``2`` in ``1+2``, whereas setting it to ``True`` results in just \ matching ``1``. That is, because in case ``include_sign`` is ``True``, ``+2`` \ is considered an integer as a whole, and as such, it cannot match when another \ digit, namely ``1``, directly precedes it. - Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in \ such a character. ''' empty = _pre.Pregex() either_sign = _op.Either('+', '-') if include_sign: if is_extensible: left_most = either_sign else: left_most = _op.Either( _asr.NonWordBoundary() + either_sign, empty.not_preceded_by(either_sign) ) else: left_most = empty super().__init__(left_most, start, end, is_extensible)
[docs]class PositiveInteger(__Integer): ''' Matches any strictly positive integer within a specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any strictly positive integer within the specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' if is_extensible: sign = _pre.Pregex('+') else: sign = _op.Either( _asr.NonWordBoundary() + '+', _pre.Pregex().not_preceded_by(_op.Either('+', '-')) ) super().__init__(sign, start, end, is_extensible)
[docs]class NegativeInteger(__Integer): ''' Matches any strictly negative integer within a specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any strictly negative integer within the specified range. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. ''' sign = (_pre.Pregex() if is_extensible else _asr.NonWordBoundary()) + "-" super().__init__(sign, start, end, is_extensible)
[docs]class UnsignedInteger(__Integer): ''' Matches any integer within a specified range, \ provided that it is not preceded by a sign. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any integer within a specified range, \ provided that it is not preceded by a sign. :param int start: The starting value of the range. Defaults to ``0``. :param int end: The ending value of the range. Defaults to ``2147483647``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either parameter ``start`` \ or parameter ``end`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than zero. - Parameter ``start`` has a greater value than that of parameter ``end``. ''' sign = _pre.Pregex().not_preceded_by(_op.Either('+', '-')) super().__init__(sign, start, end, is_extensible)
class __Decimal(_pre.Pregex): ''' Every "Decimal" class inherits from this class. :param Pregex integer_part: A ``Pregex`` instance representing the integer part. :param Pregex no_integer_part: A Pregex instance that, if not ``None``, \ is added to the pattern in order to match no integer-part numbers \ like ``.123``. :param int min_decimal: The minimum number of digits within the decimal part. :param int max_decimal: The maximum number of digits within the decimal part. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. ''' def __init__(self, integer_part: _pre.Pregex, no_integer_part: _Optional[_pre.Pregex], min_decimal: int, max_decimal: _Optional[int], is_extensible: bool) -> _pre.Pregex: ''' Every "Decimal" class inherits from this class. :param Pregex integer_part: A ``Pregex`` instance representing the integer part. :param Pregex no_integer_part: A Pregex instance that, if not ``None``, \ is added to the pattern in order to match no integer-part numbers \ like ``.123``. :param int min_decimal: The minimum number of digits within the decimal part. :param int max_decimal: The maximum number of digits within the decimal part. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. ''' if not isinstance(min_decimal, int) or isinstance(min_decimal, bool): message = "Provided argument \"min_decimal\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif min_decimal < 1: message = "Parameter \"min_decimal\" must be greater than zero." raise _ex.InvalidArgumentValueException(message) elif not isinstance(max_decimal, int) or isinstance(max_decimal, bool): if max_decimal is not None: message = "Provided argument \"max_decimal\" must be an integer." raise _ex.InvalidArgumentTypeException(message) elif min_decimal > max_decimal: message = "The value of parameter \"max_decimal\" must be greater" message += "than tha of parameter \"min_decimal\"." raise _ex.InvalidArgumentValueException(message) if no_integer_part is not None: pre = _op.Either(integer_part, no_integer_part) else: pre = integer_part pre += "." + Numeral(n_min=min_decimal, n_max=max_decimal, is_extensible=is_extensible) super().__init__(str(pre), escape=False)
[docs]class Decimal(__Decimal): ''' Matches any decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool include_sign: Determines whether to include any existing \ signs into the match. Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: - Be aware that parameter ``include_sign`` might not only play a role in \ deciding the content of the matches, but their number as well. For example, \ setting ``include_sign`` to ``False`` will result in ``Integer`` matching both \ ``1.1`` and ``2.2`` in ``1.1+2.2``, whereas setting it to ``True`` results in \ just matching ``1.1``. That is, because in case ``include_sign`` is ``True``, \ ``+2.2`` is considered a decimal number as a whole, and as such, it cannot match \ when another digit, namely ``1``, directly precedes it. - Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, min_decimal: int = 1, max_decimal: _Optional[int] = None, include_sign: bool = False, is_extensible: bool = False) \ -> _pre.Pregex: ''' Matches any decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool include_sign: Determines whether to include any existing \ signs into the match. Defaults to ``False`. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: - Be aware that parameter ``include_sign`` might not only play a role in \ deciding the content of the matches, but their number as well. For example, \ setting ``include_sign`` to ``False`` will result in ``Integer`` matching both \ ``1.1`` and ``2.2`` in ``1.1+2.2``, whereas setting it to ``True`` results in \ just matching ``1.1``. That is, because in case ``include_sign`` is ``True``, \ ``+2.2`` is considered a decimal number as a whole, and as such, it cannot match \ when another digit, namely ``1``, directly precedes it. - Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' integer_part = Integer(start, end, include_sign, is_extensible) if start == 0: no_integer_part = _pre.Pregex().not_preceded_by(_cl.AnyDigit()) if include_sign: no_integer_part += _qu.Optional(_op.Either("+", "-")) else: no_integer_part = None super().__init__(integer_part, no_integer_part, min_decimal, max_decimal, is_extensible)
[docs]class PositiveDecimal(__Decimal): ''' Matches any strictly positive decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, min_decimal: int = 1, max_decimal: _Optional[int] = None, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any positive decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' integer_part = PositiveInteger(start, end, is_extensible) if start == 0: if is_extensible: no_integer_part = _pre.Pregex().not_preceded_by(_cl.AnyDigit()) else: no_integer_part = _asr.NonWordBoundary() no_integer_part += _qu.Optional("+") else: no_integer_part = None super().__init__(integer_part, no_integer_part, min_decimal, max_decimal, is_extensible)
[docs]class NegativeDecimal(__Decimal): ''' Matches any negative decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, min_decimal: int = 1, max_decimal: _Optional[int] = None, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any negative decimal number within a specified range. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of digits within the decimal part. \ Defaults to ``1``. :param int max_decimal: The maximum number of digits within the decimal part. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' integer_part = NegativeInteger(start, end, is_extensible) if start == 0: if is_extensible: no_integer_part = _pre.Pregex().not_preceded_by(_cl.AnyDigit()) else: no_integer_part = _asr.NonWordBoundary() no_integer_part += '-' else: no_integer_part = None super().__init__(integer_part, no_integer_part, min_decimal, max_decimal, is_extensible)
[docs]class UnsignedDecimal(__Decimal): ''' Matches any decimal number within a specified range, \ provided that it is not preceded by a sign. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of decimal places. \ Defaults to ``1``. :param int max_decimal: The maximum number of decimal places. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' def __init__(self, start: int = 0, end: int = 2147483647, min_decimal: int = 1, max_decimal: _Optional[int] = None, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any decimal number within a specified range, \ provided that it is not preceded by a sign. :param int start: The starting value of the integer part range. \ Defaults to ``0``. :param int end: The ending value of the integer part range. \ Defaults to ``2147483647``. :param int min_decimal: The minimum number of decimal places. \ Defaults to ``1``. :param int max_decimal: The maximum number of decimal places. \ Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentTypeException: Either one of parameters ``start``, \ ``end``, ``min_decimal`` or ``max_decimal`` is not an integer. :raises InvalidArgumentValueException: - Parameter ``start`` has a value of less than ``0``. - Parameter ``start`` has a greater value than that of parameter ``end``. - Parameter ``min_decimal`` has a value of less than ``1``. - Parameter ``min_decimal`` has a greater value than that of parameter ``max_decimal``. :note: Even by setting parameter ``is_extensible`` to ``True``, there still persists \ an assertion that is essential to the pattern, which dictates that this pattern \ must not be preceded by any numeric characters. For that reason, one should avoid \ concatenating an instance of this class to the right of a pattern that ends in such \ a character. ''' integer_part = UnsignedInteger(start, end, is_extensible) if start == 0: if is_extensible: no_integer_part = _pre.Pregex().not_preceded_by( _op.Either('+', '-', _cl.AnyDigit())) else: no_integer_part = _asr.NonWordBoundary().not_preceded_by(_op.Either('+', '-')) else: no_integer_part = None super().__init__(integer_part, no_integer_part, min_decimal, max_decimal, is_extensible)
[docs]class Date(_pre.Pregex): ''' Matches any date within a range of predefined formats. :param str | list[str] formats: Either a string or a list of strings \ through which it is determined what are the exact date formats that \ are to be considered possible matches. A valid date format can be \ either one of: - ``D<sep>M<sep>Y`` - ``M<sep>D<sep>Y`` - ``Y<sep>M<sep>D`` where: - ``<sep>``: Either ``/`` or ``-`` - ``D``: Either one of the following: - ``d``: one-digit day of the month for days below 10, e.g. 2 - ``dd``: two-digit day of the month, e.g. 02 - ``M``: Either one of the following: - ``m``: one-digit month for months below 10, e.g. 3 - ``mm``: two-digit month, e.g. 03 - ``Y``: Either one of the following: - ``yy``: two-digit year, e.g. 21 - ``yyyy``: four-digit year, e.g. 2021 For example, ``dd/mm/yyyy`` is considered a valid date format whereas \ ``mm/yyyy/dd`` is not. Lastly, If ``None`` is provided in place of this \ list, then all possible formats are considered. Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentValueException: At least one of the provided arguments \ is not a valid date format. ''' __date_separators: tuple[str, str] = ("-", "/") def __init__(self, formats: _Optional[_Union[str, list[str]]] = None, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any date within a range of predefined formats. :param str | list[str] formats: Either a string or a list of strings \ through which it is determined what are the exact date formats that \ are to be considered possible matches. A valid date format can be \ either one of: - ``D<sep>M<sep>Y`` - ``M<sep>D<sep>Y`` - ``Y<sep>M<sep>D`` where: - ``<sep>``: Either ``/`` or ``-`` - ``D``: Either one of the following: - ``d``: one-digit day of the month for days below 10, e.g. 2 - ``dd``: two-digit day of the month, e.g. 02 - ``M``: Either one of the following: - ``m``: one-digit month for months below 10, e.g. 3 - ``mm``: two-digit month, e.g. 03 - ``Y``: Either one of the following: - ``yy``: two-digit year, e.g. 21 - ``yyyy``: four-digit year, e.g. 2021 For example, ``dd/mm/yyyy`` is considered a valid date format whereas \ ``mm/yyyy/dd`` is not. Lastly, If ``None`` is provided in place of this \ list, then all possible formats are considered. Defaults to ``None``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :raises InvalidArgumentValueException: At least one of the provided arguments \ is not a valid date format. ''' date_formats = __class__.__date_formats() formats = date_formats if formats is None else formats if isinstance(formats, str): formats = [formats] dates: list[_pre.Pregex] = [] for format in formats: if format not in date_formats: message = f"Provided date format \"{format}\" is not valid." raise _ex.InvalidArgumentValueException(message) dates.append(__class__.__date_pre(format)) pre = _op.Either(*dates) if not is_extensible: pre = pre.enclose(_asr.WordBoundary()) super().__init__(str(pre), escape=False) def __date_pre(format: str) -> _pre.Pregex: """ Converts a date format into a ``Pregex`` instance. :param str format: The date format to be converted. """ format = format.lower() for sep in __class__.__date_separators: if sep in format: separator = sep break values = format.split(separator) any_digit_but_zero = _cl.AnyDigit() - '0' either_zero_or_one = _op.Either('0', '1') either_one_or_two = _op.Either('1', '2') date_to_pre: dict[str, _pre.Pregex] = { 'd': any_digit_but_zero, 'dd': _op.Either( '0' + any_digit_but_zero, either_one_or_two.either('3') + \ _op.Either( _cl.AnyDigit().preceded_by(either_one_or_two), either_zero_or_one.preceded_by('3') )), 'm': any_digit_but_zero, 'mm': _op.Either( '0' + any_digit_but_zero, '1' + either_zero_or_one.either('2')), 'yy': _cl.AnyDigit() * 2, 'yyyy': _cl.AnyDigit() * 4, } pre = _pre.Pregex() for i, value in enumerate(values): pre += date_to_pre[value] if i < len(values) - 1: pre += separator return pre @staticmethod def __date_formats() -> list[str]: ''' Returns a list containing all possible date format combinations. ''' day = ("dd", "d") month = ("mm", "m") year = ("yyyy", "yy") date_formats: list[tuple[str, str, str]] = [] for d in day: for m in month: for y in year: date_formats.append((d, m, y)) date_formats.append((m, d, y)) date_formats.append((y, m, d)) return [sep.join(df) for df in date_formats for sep in __class__.__date_separators]
[docs]class IPv4(_pre.Pregex): ''' Matches any IPv4 Address. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. ''' def __init__(self, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any IPv4 Address. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. ''' any_digit_but_zero = _cl.AnyDigit() - '0' any_digit_up_to_four = _cl.AnyBetween('0', '4') ip_octet = _op.Either( _cl.AnyDigit(), any_digit_but_zero + _cl.AnyDigit(), '1' + 2 * _cl.AnyDigit(), '2' + _op.Either( any_digit_up_to_four + _cl.AnyDigit(), '5' + (any_digit_up_to_four | '5') ) ) pre = 3 * (ip_octet + ".") + ip_octet if not is_extensible: pre = pre.not_enclosed_by(_op.Either(_cl.AnyDigit(), ".")) super().__init__(str(pre), escape=False)
[docs]class IPv6(_pre.Pregex): ''' Matches any IPv6 Address. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. ''' def __init__(self, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any IPv6 Address. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. ''' hex_group = Numeral(base=16, n_min=1, n_max=4, is_extensible=is_extensible) pre = 7 * (hex_group + ":") + hex_group empty = _pre.Pregex() for i in range(9): pre = _op.Either( pre, (_qu.AtLeastAtMost(hex_group + ":", n=0, m=i-1) if i > 1 else empty) + \ (hex_group if i > 0 else empty) + \ "::" + \ (_qu.AtLeastAtMost(hex_group + ":", n=0, m=7-i) if i < 7 else empty)+ \ (hex_group if i < 8 else empty) ) pre = _op.Either(pre, "::") if not is_extensible: pre = pre.not_enclosed_by(_op.Either(_cl.AnyDigit(), ":")) super().__init__(str(pre), escape=False)
[docs]class Email(_pre.Pregex): ''' Matches any email address. :param bool capture_local_part: If set to ``True``, then the local-part \ of each email address match is separately captured as well. Defaults \ to ``False``. :param bool capture_domain: If set to ``True``, then the domain name \ of each email address match is separately captured as well. \ Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :note: Not guaranteed to match every possible email address. ''' def __init__(self, capture_local_part: bool = False, capture_domain: bool = False, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any email address. :param bool capture_local_part: If set to ``True``, then the local-part \ of each Email address match is separately captured as well. Defaults \ to ``False``. :param bool capture_domain: If set to ``True``, then the domain name \ of each Email address match is separately captured as well. \ Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :note: Not guaranteed to match every possible e-mail address. ''' potential_word_boundary = _pre.Pregex() if is_extensible else _asr.WordBoundary() potential_non_word_boundary = _pre.Pregex() if is_extensible else _asr.NonWordBoundary() special = _cl.AnyFrom('!', '#', '$', '%', "'", '*', '+', '-', '/', '=', '?', '^', '_', '`', '{', '|', '}', '~') alphanum = _cl.AnyLetter() | _cl.AnyDigit() local_part_valid_char = alphanum | special left_most = _op.Either( potential_non_word_boundary.followed_by(special), potential_word_boundary.followed_by(alphanum) ) local_part = \ (local_part_valid_char - '-') + \ _qu.AtMost( _op.Either(local_part_valid_char, _asr.NotFollowedBy('.', '.')), n=62 ) + \ (local_part_valid_char - '-') if capture_local_part: local_part = _gr.Capture(local_part) domain_name = \ alphanum + \ _qu.AtMost(alphanum | "-", n=61) + \ alphanum subdomains = _qu.Indefinite(domain_name + ".") if capture_domain: domain_name = _gr.Capture(domain_name) tld = "." + _qu.AtLeastAtMost(_cl.AnyLowercaseLetter(), n=2, m=6) pre = left_most + local_part + '@' + subdomains + domain_name \ + tld + potential_word_boundary super().__init__(str(pre), escape=False)
[docs]class HttpUrl(_pre.Pregex): ''' Matches any HTTP URL. :param bool capture_domain: If set to ``True``, then the domain name \ of each URL match is separately captured as well. Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :note: Not guaranteed to match every possible HTTP URL. ''' def __init__(self, capture_domain: bool = False, is_extensible: bool = False) -> _pre.Pregex: ''' Matches any HTTP URL. :param bool capture_domain: If set to ``True``, then the domain name \ of each URL match is separately captured as well. Defaults to ``False``. :param bool is_extensible: If ``True``, then no additional assertions \ are imposed upon the underlying pattern, other than any necessary ones, \ which in turn prevents certain complications from arising whenever it \ serves as a building block to a larger pattern. As a general rule of thumb, \ set this parameter to ``True`` if you wish to extend the resulting instance's \ underlying pattern, or to ``False`` if you are only using it for matching purposes. \ Defaults to ``False``. :note: Not guaranteed to match every possible HTTP URL. ''' potential_word_boundary = _pre.Pregex() if is_extensible else _asr.WordBoundary() potential_non_word_boundary = _pre.Pregex() if is_extensible else _asr.NonWordBoundary() left_most = potential_word_boundary http_protocol = _qu.Optional("http" + _qu.Optional('s') + "://") www = _qu.Optional("www.") alphanum = _cl.AnyLetter() | _cl.AnyDigit() domain_name = \ alphanum + \ _qu.AtMost(alphanum | "-", n=61) + \ alphanum subdomains = _qu.Indefinite(domain_name + ".") tld = "." + _cl.AnyLowercaseLetter().at_least_at_most(n=2, m=6) optional_port = _qu.Optional(":" + _cl.AnyDigit().at_least_at_most(n=1, m=4)) directories = _qu.Indefinite( "/" + \ _qu.OneOrMore(_cl.AnyWordChar(is_global=True) | (_cl.AnyPunctuation() - "/")) ) + _qu.Optional("/") right_most = _op.Either( potential_non_word_boundary.preceded_by(_cl.AnyPunctuation()), potential_word_boundary.preceded_by(_cl.AnyWordChar(is_global=True)) ) if capture_domain: domain_name = _gr.Capture(domain_name) pre = left_most + http_protocol + www + subdomains + \ domain_name + tld + optional_port + directories + right_most super().__init__(str(pre), escape=False)