<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <a href="https
Step2:  Let's make some examples using regexps
Pattern in string
Step3:  re.match searches for the pattern only at the beginning of string. It returns an object or None if the pattern not found.
Step4:  re.search searches the first occurence of the pattern in the string.
Step5:  r preface is often used for regular expression
Step6:  We can use regexp to find/match functions to validate input data. In the example below, is a string a valid number?
Step7:  There is another approach to check numerical values without regexp, as follows
Step8:  Email address validation
Step9:  Other functions
re.sub replaces the occurrence of a regexp with a given text in a string.
Step10:  re.split splits a text into a list of parts, where separators are given by regexp.
Step11:  Please note that the previous result contains some empty words where two or more separators are adjecent. Let's correct it
Step12:  Why is there an empty word at the end?
Complex example
Let's make a complex example
<ASSISTANT_TASK:>
Python Code:
import re
Explanation: <a href="https://colab.research.google.com/github/OSGeoLabBp/tutorials/blob/master/english/python/regexp_in_python.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
Regular expressions in Python
Regular expression (regexp) is a powerful tool to handle diverse text patterns in text processing. Several text editors (e.g Notepad++, vi) and programming languages have regexp functionality.
To define text patterns, a special meaning is assigned to some characters. You can find below a very short and incomplete list of special regexp characters:
|character(s)|explanation                                                      |
|------------|-----------------------------------------------------------------|
|. (dot)     | any character except new line                                   |
|^           |beginning of the line                                            |
|$           |end of the line                                                  |
|[abc]       |any character from the set in the brackets                       |
|[^abc]      |none of the characters in the set in brackets                    |
|[a-z]       |any character from the range in brackets (inclusive)             |
|[^a-z]      |none of the characters in the range in brackets                  |
|( )         |make group in pattern                                            |
|{min,max}   | repetition of the previous character or group, max part is optional|
|p1 \| p2    |p1 pattern or p2 pattern                                         |
|p*         |any number of repetition of p pattern, including zero equivalent to p{0,}|
|p+          |one or more repetition of p pattern, equivalent to p{1,}         |
|p?          |zero or one repetition of p pattern, equivalent to p{0,1}        |
|\           |escape the special meaning of the next character (e.g. . the dot character, not any character)|
Python has a special package named re to handle regular expressions. To use it, it is necessary to import it, as follows:
End of explanation
text = Python is an interpreted high-level general-purpose programming language. 
Its design philosophy emphasizes code readability with its use of significant indentation. 
Its language constructs as well as its object-oriented approach aim to help programmers write clear, 
logical code for small and large-scale projects.   # citation from Wikipedia
Explanation: Let's make some examples using regexps
Pattern in string
End of explanation
re.match("Python", text)      # is Python at the beginning of the text?
if re.match("[Pp]ython", text): # is Python or python at the beginning of the text?
  print('text starts with Python')
result = re.match("[Pp]ython", text)
result.span(), result.group(0)
Explanation: re.match searches for the pattern only at the beginning of string. It returns an object or None if the pattern not found.
End of explanation
re.search('prog', text)
re.search('levels?', text)        # optional 's' after level
re.findall('pro', text)
Explanation: re.search searches the first occurence of the pattern in the string.
End of explanation
re.findall(r'[ \t\r\n]a[a-zA-Z0-9_][ \t\r\n]', text) # two letter words starting with letter 'a'
re.findall(r'\sa\w\s', text)   # the same as above but shorter       
re.findall(r'\sa\w*\s', text)    # words strarting with 'a'
Explanation: r preface is often used for regular expression
End of explanation
int_numbers = ('12356', '1ac', 'twelve', '23.65', '0', '-768')
for int_number in int_numbers:
  if re.match(r'[+-]?(0|[1-9][0-9]*)$', int_number):
    print(f'{int_number} is an integer number')
float_numbers =('12', '0.0', '-43.56', '1.76e-1', '1.1.1', '00.289')
for float_number in float_numbers:
  if re.match(r'[+-]?(0|[1-9][0-9]*)(\.[0-9]*)?([eg][+-]?[0-9]+)?$', float_number):
    print(f'{float_number} is a float number')
Explanation: We can use regexp to find/match functions to validate input data. In the example below, is a string a valid number?
End of explanation
for float_number in float_numbers:
  try:
    float(float_number)     # try to convert to float number
  except ValueError:
    continue                # can't convert skip it
  print(f'{float_number} is a float number')
Explanation: There is another approach to check numerical values without regexp, as follows:
End of explanation
email = re.compile(r'^[a-zA-Z0-9.!#$%&\'*+/=?^_`{|}~-]+@[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$')
addresses = ['a.b@c', 'siki.zoltan@emk.bme.hu', 'plainaddress', '#@%^%#$@#$@#.com', '@example.com', 'Joe Smith <email@example.com>',
            'email.example.com', 'email@example@example.com', 'email@123.123.123.123']
valid_addresses = [addr for addr in addresses if email.search(addr)]
print('valid email addresses:\n', valid_addresses)
invalid_addresses = [addr for addr in addresses if not email.search(addr)]
print('invalid email addresses:\n', invalid_addresses)
Explanation: Email address validation: We'll use the precompiled regular expression (re.compile). This alternative is faster than the alternative of using the same regexp evaluated several times:
End of explanation
print(re.sub(r'  *', ' ', 'Text     with     several unnecessary    spaces')) # truncate adjecent spaces to a single space
print(re.sub(r'[ \t,;]', ',', 'first,second;third fourth fifth'))             # unify separators
Explanation: Other functions
re.sub replaces the occurrence of a regexp with a given text in a string.
End of explanation
words = re.split(r'[, \.\t\r\n]', text)   # word separators are space, dot, tabulator and EOL
words
Explanation: re.split splits a text into a list of parts, where separators are given by regexp.
End of explanation
words = re.split(r'[, \.\t\r\n]+', text)  # join adjecent separators
words
Explanation: Please note that the previous result contains some empty words where two or more separators are adjecent. Let's correct it:
End of explanation
import urllib.request
url = 'https://www.gutenberg.org/files/236/236-0.txt'
words = {}
with urllib.request.urlopen(url) as file:
  for line in file:
    ws = re.split(r'[, \.\t\r\n]+', line.decode('utf8'))
    for w in ws:
      w = w.lower()
      if re.match('[sS][a-z]{3}', w):
        if w in words:
          words[w] += 1
        else:
          words[w] = 1
print(f'{len(words.keys())} different four letter words starting with "s"')
m = max(words, key=words.get)
print(f'{m}: {words[m]}')
Explanation: Why is there an empty word at the end?
Complex example
Let's make a complex example: Find the most frequent four-letter word starting with "s" in Kipling's The Jungle Book.
End of explanation
<END_TASK>