import re

r = re.compile("abc")
type(r), r

m = r.search("aabcd")
type(m), m

"""
Explanation: Regular expressions
Regular expressions (regex or regexp) are search patterns described as strings. They allow pattern matching in arbitrary strings.
Regex are implemented in Python's re module.
The re module operates via two objects:

pattern objects, which are a compiled regular expressions and
match objects that describe successful pattern matches.
End of explanation
"""


m2 = r.search("def")
m2

"""
Explanation: or None is returned when no matching pattern was found in the string
End of explanation
"""


m = r.search("aabcde")
m.span()

m.start(), m.end()

"""
Explanation: The match object's span method returns the starting and ending index of the match:
End of explanation
"""


s = "aabcdef"
m = r.search(s)

s[m.start():m.end()]

"""
Explanation: these can be directly used to extract the matching substring:
End of explanation
"""


re.search("ab", "abcd")

"""
Explanation: Pattern objects do not have to be created but compilation offers some speed-up.
End of explanation
"""


re.search("[bB]", "abc")

re.search("[bB]", "aBb")

"""
Explanation: Basic regular expressions
Below we show the most commonly used regex types. For a full list see the official documentation here.
We will not compile the regular expressions for the sake of brevity.
For capturing a range of characters, use []:
End of explanation
"""


re.search("a?bc", "bc")

re.search("a?bc", "aabc")

"""
Explanation: Qualifiers
Qualifiers control how many times a pattern is searched for.
? matches zero or one time:
End of explanation
"""


re.search("a*bc", "aaabc")

"""
Explanation: * matches zero or more times in a greedy manner (match as many as possible):
End of explanation
"""


re.search("a+bc", "daaaabc")

"""
Explanation: + matches one or more times:
End of explanation
"""


re.search("a{3}bc", "aabc")

re.search("a{3}bc", "aaaabc")

"""
Explanation: {N} will match exactly $N$ times:
End of explanation
"""


re.search("a{3,5}bc", "aaaabc")

re.search("a{3,5}bc", "aaaaabc")

"""
Explanation: {N,M} will match at least $N$ and at most $M$ times:
End of explanation
"""


re.search("a.c", "abc")

print(re.search("a.c", "ac"))

"""
Explanation: Special characters
. matches any character besides newline:
End of explanation
"""


re.search("^a", "abc"), re.search("^a", "bc\na")

re.search("^a", "bc\nab", re.MULTILINE)

"""
Explanation: ^ (Caret) matches the beginning of the string and in MULTILINE mode, immediately after each newline:
End of explanation
"""


re.search("c$", "abc")

re.search("a$", "aba\nc", re.MULTILINE)

"""
Explanation: $ matches the end of the string or before newline in MULTILINE mode:
End of explanation
"""


re.search("[A-F]{3}", "abBCDEef")

"""
Explanation: Character ranges
[A-F] matches every character between A and F:
End of explanation
"""


re.search("[A-Za-z]+", "abAaz12")

"""
Explanation: [A-Za-z] matches every English letter:
End of explanation
"""


re.search("[0-9]{3}", "ab12345cd")

"""
Explanation: [0-9] matches digits:
End of explanation
"""


re.search("[0-9\-]+", "1-2")

"""
Explanation: - needs to be escaped if we want to include it in the character range:
End of explanation
"""


re.search("\s+", "ab \t\n\n")

"""
Explanation: Character classes
Some character classes are predefined such as ascii letters or whitespaces.
\s matches any Unicode whitespace:
End of explanation
"""


re.search("\S+", "ab \t\n\n")

"""
Explanation: \S (capital S) matches anything else:
End of explanation
"""


re.search("\w+", "tükőrfúrógép")

re.search("\w+", "tükőr fúrógép")

"""
Explanation: \w matches any Unicode word character that can be part of a word in any language, and \W matches anything else:
End of explanation
"""


patt = re.compile("([hH]ell[oó]) (.*)!")
match = patt.search("Hello people!")

match.group()

match.groups()

match.group(0)

match.group(1)

match.group(2)

"""
Explanation: Capture groups
Patterns may contain groups, marked by parentheses. Groups can be accessed by their indices, or all of them can be retrieved by the groups method:
End of explanation
"""


patt = re.compile("(?P<greeting>[hH]ell[oó]) (?P<name>.*)!")
match = patt.search("Hello people!")
match.group("name")

match.groupdict()

"""
Explanation: Groups can also be named, in this case they can be retrieved in a dict maping group names to matched substrings using groupdict:
End of explanation
"""


re.match("ab", "abcd")

print(re.match("ab", "zabcd"))

"""
Explanation: Other re methods
re.match matches only at the beginning of the string
End of explanation
"""


re.findall("[AaBb]+", "ab Abcd")

"""
Explanation: re.findall matches every occurrence of a pattern in a string. Unlike most other methods, findall directly returns the string patterns instead of patter objects.
End of explanation
"""


for match in re.finditer("[AaBb]+", "ab Abcd"):
    print(match)

"""
Explanation: re.findall returns an iterator that iterates over every match:
End of explanation
"""


re.sub("[Aa]", "b", "acA")

re.split("\s+", "words  with\t whitespace")

"""
Explanation: re.sub replaces an occurrence:
End of explanation
"""


