TODO (these are very roughly in order):
I read the string docs wrong: instead of using a custom parser, use the builtin string parser for the replace() function
nested_expr(opener, closer, content=None, ignore_expr=quoted_string) - method for defining nested lists enclosed in opening and closing delimiters.
maybe change conditionals to taking in 2 parameters (the current pattern, and their associated condition) instead
all the methods which return NotImplemented
fix anyExcept
Look into the __format__() dunder method for auto-calling compile with strings
(?:(?:a|b)|c) does not do the same as ((a|b)|c). Why? Is this intentional?
operators: |, &, ^, ~
wordStart/wordEnd/wordStartsWith/wordEndsWith \<	Start of word and \>	End of word
maybe a function like line(stuff in a line), which automatically adds line start and line end to it
& and `and` operator -- Each
Add these https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html#expression-operators
DelimitedList - used for matching one or more occurrences of expr, separated by delim.
?>	Once-only Subexpression
add ezregex.org to the homepage link in PyPi
something like a word(letters=n) or something, including \b word{3} \b
CaselessLiteral - construct with a string to be matched, but without case checking; results are always returned as the defining literal, NOT as they are found in the input string
caseless_literal -- a caseless function that makes only the specified chain case-insensitive. Might only work on a few funtions?
nested groups (i.e. matchMax(group(comma))) will only match the last one. Add some way to fix that?
QuotedString - supports the definition of custom quoted string formats, in addition to pyparsing’s built-in dbl_quoted_string and sgl_quoted_string. QuotedString allows you to specify the following parameters:
Keyword - similar to Literal, but must be immediately followed by whitespace, punctuation, or other non-keyword characters; prevents accidental matching of a non-keyword that happens to begin with a defined keyword
arith_op
These https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html#common-string-and-token-constants
empty -- matches an empty string in an expression. useful for something like empty + ifFollowedBy(...)
expr[...:end_expr] is equivalent to ZeroOrMore(expr, stop_on=end_expr)
CaselessKeyword - similar to Keyword, but with caseless matching behavior as described in CaselessLiteral.
ungroup
NotAny - a negative lookahead expression, prevents matching of named expressions, does not advance the parsing position within the input string; can also be created using the unary ‘~’ operator
is matchMax(either('a', 'b')) supposed to match 'aba' or just 'aaa' or 'bbb'?
emoji() member
look into including the unicodedata built in python library?
methods like __and__ and __or__ which add regex directly don't take into account dialects
\Q	Begin literal sequence
\E	End literal sequence
(?#...) comment because why not
Everything on https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html#basic-parserelement-subclasses for compatibility
(?>...) -- Attempts to match ... as if it was a separate regular expression, and if successful, continues to match the rest of the pattern following it. If the subsequent pattern fails to match, the stack can only be unwound to a point before the (?>...) because once exited, the expression, known as an atomic group, has thrown away all stack points within itself. Thus, (?>.*). would never match anything because first the .* would match all characters possible, then, having nothing left to match, the final . would fail to match. Since there are no stack points saved in the Atomic Group, and there is no stack point before it, the entire expression would thus fail to match.
more flags listed under https://pypi.org/project/regex/ under "Flags".
content - expression for items within the nested lists (default=None)


BUGS:
AnyExcept tests are currently failing == AnyExcept: ^(?!.*county).* (matches any line which doesn't have 'county' in it)
| operator isn't working for some reason
try matchRange(0, 3, digit) matching 8888888, and see how many matches it finds
invert, when matching upper and lowercase, seem to only choose a or z
Invert is failing some tests
inverting possesive parameters causes a recursion error (optional(anyCharExcept('{'), possessive=True) + '{' + group(+alphaNum) + '}' + optional(anyCharExcept('}'), greedy=False))


ADD TESTS FOR:
Fix anyExcept, but of a specific type (i.e. anything which is a word, but not in args)
punctuation
All the todos in tests
more lookahead, lookbehinds
<<=, >>=
some psuedonymns
more flags
wordBoundary
notWordBoundary
matchRange
isEnclosedWith
atLeastOne
Go through all the elements and oduble check they all have tests


ADD DOCS FOR:
anyExcept, but of a specific type (i.e. anything which is a word, but not in args)
Make the .test() example in the readme be colored (probably using HTML)


ADD INVERTS FOR:
`(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)` (Failed expr: was `g@zZf.G>`)


TO INVESTIGATE:
    p = wordChar; s = '5_5';
        not enough matches presented, and splitting seems off
