prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Lexicon process for Latin fails on regex special characters
  LatinLexiconProcess fails when regex special characters, e.g. single open parenthesis (i.e. ```(```) are included in tokenized input. Occurred while running MacOS 11.4; Python 3.9.5; CLTK 1.0.15; regex 2021.4.4 (but should fail in any case when this input is passed to the regex module). The solution is to escape the input ```lemma``` before running ```regex.match``` at https://github.com/cltk/cltk/blob/5dbfcf6fccade146d322cae036b35533aec59286/src/cltk/lexicon/lat.py#L70
  
  I have written the patch and will make a PR soon.
  
  Example and traceback:
  
  ```
  from cltk import NLP
  text = "Omnes igitur partes mundi (tangam autem maximas) calore fultae sustinentur." # Cic. Nat. D. 2.25
  cltk_nlp = NLP(language="lat")
  cltk_doc = cltk_nlp.analyze(text=test)
  ```
  
  ```
  Traceback (most recent call last):
    File "test.py", line 4, in <module>
      cltk_doc = cltk_nlp.analyze(text=text)
    File "[PATH]/lib/python3.9/site-packages/cltk/nlp.py", line 142, in analyze
      doc = a_process.run(doc)
    File "[PATH]/lib/python3.9/site-packages/cltk/lexicon/processes.py", line 45, in run
      word.definition = lookup_algo.lookup(word.lemma)
    File "[PATH]/lib/python3.9/site-packages/cltk/lexicon/lat.py", line 70, in lookup
      matches = [key for key in keys if regex.match(rf"^{lemma}[0-9]?$", key)]
    File "[PATH]/lib/python3.9/site-packages/cltk/lexicon/lat.py", line 70, in <listcomp>
      matches = [key for key in keys if regex.match(rf"^{lemma}[0-9]?$", key)]
    File "[PATH]/lib/python3.9/site-packages/regex/regex.py", line 253, in match
      pat = _compile(pattern, flags, ignore_unused, kwargs, True)
    File "[PATH]/lib/python3.9/site-packages/regex/regex.py", line 532, in _compile
      raise error(caught_exception.msg, caught_exception.pattern,
  regex._regex_core.error: missing ) at position 9
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/cltk/lexicon/lat.py`
  Content:
  ```
  1 """Code for querying Latin language dictionaries/lexicons."""
  2 
  3 import regex
  4 import yaml
  5 
  6 from cltk.core.exceptions import CLTKException
  7 from cltk.data.fetch import FetchCorpus
  8 from cltk.utils.file_operations import make_cltk_path
  9 from cltk.utils.utils import query_yes_no
  10 
  11 __author__ = ["Clément Besnier <clem@clementbesnier.fr>"]
  12 
  13 
  14 class LatinLewisLexicon:
  15     """Access a digital form of Charlton T. Lewis's *An Elementary Latin Dictionary* (1890)."""
  16 
  17     def __init__(self, interactive: bool = True):
  18         self.interactive = interactive
  19         self.lewis_yaml_fp = make_cltk_path(
  20             "lat", "lexicon", "cltk_lat_lewis_elementary_lexicon", "lewis.yaml"
  21         )
  22         try:
  23             self.entries = self._load_entries()
  24         except FileNotFoundError:
  25             if self.interactive:
  26                 dl_msg = f"This part of the CLTK depends upon Lewis's *An Elementary Latin Dictionary* (1890)."
  27                 print(dl_msg)
  28                 dl_question = "Do you want to download this?"
  29                 do_download = query_yes_no(question=dl_question)
  30             else:
  31                 do_download = True
  32             if do_download:
  33                 fetch_corpus = FetchCorpus(language="lat")
  34                 fetch_corpus.import_corpus(
  35                     corpus_name="cltk_lat_lewis_elementary_lexicon"
  36                 )
  37             else:
  38                 raise CLTKException(
  39                     f"File '{self.lewis_yaml_fp}' is not found. It is required for this class."
  40                 )
  41             self.entries = self._load_entries()
  42 
  43     def lookup(self, lemma: str) -> str:
  44         """Perform match of a lemma against headwords. If more than one match,
  45         then return the concatenated entries. For example:
  46 
  47         >>> lll = LatinLewisLexicon()
  48         >>> lll.lookup("clemens")[:50]
  49         'clēmēns entis (abl. -tī; rarely -te, L.), adj. wit'
  50         >>> lll.lookup("omnia")
  51         ''
  52         >>> lll.lookup(".")
  53         ''
  54         >>> lll.lookup("123")
  55         ''
  56         >>> lll.lookup("175.")
  57         ''
  58         """
  59         if not self.entries:
  60             raise CLTKException(
  61                 "No lexicon entries found in the .yaml file. This should never happen."
  62             )
  63 
  64         if regex.match(r"^[0-9\.\?,\:;\!\<\>\-]*$", lemma) is not None:
  65             return ""
  66 
  67         lemma = lemma.lower()
  68 
  69         keys = self.entries.keys()
  70         matches = [key for key in keys if regex.match(rf"^{lemma}[0-9]?$", key)]
  71         n_matches = len(matches)
  72         if n_matches > 1:
  73             return "\n".join([self.entries[key] for key in matches])
  74         elif n_matches == 1:
  75             return self.entries[matches[0]]
  76         else:
  77             return ""
  78 
  79     def _load_entries(self):
  80         """Read the yaml file of the lexion."""
  81         with open(self.lewis_yaml_fp) as file_open:
  82             entries = yaml.load(file_open, Loader=yaml.Loader)
  83         return entries
  84
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/cltk/lexicon/lat.py b/src/cltk/lexicon/lat.py
  --- a/src/cltk/lexicon/lat.py
  +++ b/src/cltk/lexicon/lat.py
  @@ -47,6 +47,8 @@
           >>> lll = LatinLewisLexicon()
           >>> lll.lookup("clemens")[:50]
           'clēmēns entis (abl. -tī; rarely -te, L.), adj. wit'
  +        >>> all(word in lll.lookup("levis") for word in ["levis","lēvis"]) # Test for concatenated entries
  +        True
           >>> lll.lookup("omnia")
           ''
           >>> lll.lookup(".")
  @@ -55,6 +57,8 @@
           ''
           >>> lll.lookup("175.")
           ''
  +        >>> lll.lookup("(") # Test for regex special character
  +        ''
           """
           if not self.entries:
               raise CLTKException(
  @@ -64,7 +68,7 @@
           if regex.match(r"^[0-9\.\?,\:;\!\<\>\-]*$", lemma) is not None:
               return ""
   
  -        lemma = lemma.lower()
  +        lemma = regex.escape(lemma.lower())
   
           keys = self.entries.keys()
           matches = [key for key in keys if regex.match(rf"^{lemma}[0-9]?$", key)]
  
verification_info: {"golden_diff": "diff --git a/src/cltk/lexicon/lat.py b/src/cltk/lexicon/lat.py\n--- a/src/cltk/lexicon/lat.py\n+++ b/src/cltk/lexicon/lat.py\n@@ -47,6 +47,8 @@\n         >>> lll = LatinLewisLexicon()\n         >>> lll.lookup(\"clemens\")[:50]\n         'cl\u0113m\u0113ns entis (abl. -t\u012b; rarely -te, L.), adj. wit'\n+        >>> all(word in lll.lookup(\"levis\") for word in [\"levis\",\"l\u0113vis\"]) # Test for concatenated entries\n+        True\n         >>> lll.lookup(\"omnia\")\n         ''\n         >>> lll.lookup(\".\")\n@@ -55,6 +57,8 @@\n         ''\n         >>> lll.lookup(\"175.\")\n         ''\n+        >>> lll.lookup(\"(\") # Test for regex special character\n+        ''\n         \"\"\"\n         if not self.entries:\n             raise CLTKException(\n@@ -64,7 +68,7 @@\n         if regex.match(r\"^[0-9\\.\\?,\\:;\\!\\<\\>\\-]*$\", lemma) is not None:\n             return \"\"\n \n-        lemma = lemma.lower()\n+        lemma = regex.escape(lemma.lower())\n \n         keys = self.entries.keys()\n         matches = [key for key in keys if regex.match(rf\"^{lemma}[0-9]?$\", key)]\n", "issue": "Lexicon process for Latin fails on regex special characters\nLatinLexiconProcess fails when regex special characters, e.g. single open parenthesis (i.e. ```(```) are included in tokenized input. Occurred while running MacOS 11.4; Python 3.9.5; CLTK 1.0.15; regex 2021.4.4 (but should fail in any case when this input is passed to the regex module). The solution is to escape the input ```lemma``` before running ```regex.match``` at https://github.com/cltk/cltk/blob/5dbfcf6fccade146d322cae036b35533aec59286/src/cltk/lexicon/lat.py#L70\r\n\r\nI have written the patch and will make a PR soon.\r\n\r\nExample and traceback:\r\n\r\n```\r\nfrom cltk import NLP\r\ntext = \"Omnes igitur partes mundi (tangam autem maximas) calore fultae sustinentur.\" # Cic. Nat. D. 2.25\r\ncltk_nlp = NLP(language=\"lat\")\r\ncltk_doc = cltk_nlp.analyze(text=test)\r\n```\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"test.py\", line 4, in <module>\r\n    cltk_doc = cltk_nlp.analyze(text=text)\r\n  File \"[PATH]/lib/python3.9/site-packages/cltk/nlp.py\", line 142, in analyze\r\n    doc = a_process.run(doc)\r\n  File \"[PATH]/lib/python3.9/site-packages/cltk/lexicon/processes.py\", line 45, in run\r\n    word.definition = lookup_algo.lookup(word.lemma)\r\n  File \"[PATH]/lib/python3.9/site-packages/cltk/lexicon/lat.py\", line 70, in lookup\r\n    matches = [key for key in keys if regex.match(rf\"^{lemma}[0-9]?$\", key)]\r\n  File \"[PATH]/lib/python3.9/site-packages/cltk/lexicon/lat.py\", line 70, in <listcomp>\r\n    matches = [key for key in keys if regex.match(rf\"^{lemma}[0-9]?$\", key)]\r\n  File \"[PATH]/lib/python3.9/site-packages/regex/regex.py\", line 253, in match\r\n    pat = _compile(pattern, flags, ignore_unused, kwargs, True)\r\n  File \"[PATH]/lib/python3.9/site-packages/regex/regex.py\", line 532, in _compile\r\n    raise error(caught_exception.msg, caught_exception.pattern,\r\nregex._regex_core.error: missing ) at position 9\r\n```\n", "before_files": [{"content": "\"\"\"Code for querying Latin language dictionaries/lexicons.\"\"\"\n\nimport regex\nimport yaml\n\nfrom cltk.core.exceptions import CLTKException\nfrom cltk.data.fetch import FetchCorpus\nfrom cltk.utils.file_operations import make_cltk_path\nfrom cltk.utils.utils import query_yes_no\n\n__author__ = [\"Cl\u00e9ment Besnier <clem@clementbesnier.fr>\"]\n\n\nclass LatinLewisLexicon:\n    \"\"\"Access a digital form of Charlton T. Lewis's *An Elementary Latin Dictionary* (1890).\"\"\"\n\n    def __init__(self, interactive: bool = True):\n        self.interactive = interactive\n        self.lewis_yaml_fp = make_cltk_path(\n            \"lat\", \"lexicon\", \"cltk_lat_lewis_elementary_lexicon\", \"lewis.yaml\"\n        )\n        try:\n            self.entries = self._load_entries()\n        except FileNotFoundError:\n            if self.interactive:\n                dl_msg = f\"This part of the CLTK depends upon Lewis's *An Elementary Latin Dictionary* (1890).\"\n                print(dl_msg)\n                dl_question = \"Do you want to download this?\"\n                do_download = query_yes_no(question=dl_question)\n            else:\n                do_download = True\n            if do_download:\n                fetch_corpus = FetchCorpus(language=\"lat\")\n                fetch_corpus.import_corpus(\n                    corpus_name=\"cltk_lat_lewis_elementary_lexicon\"\n                )\n            else:\n                raise CLTKException(\n                    f\"File '{self.lewis_yaml_fp}' is not found. It is required for this class.\"\n                )\n            self.entries = self._load_entries()\n\n    def lookup(self, lemma: str) -> str:\n        \"\"\"Perform match of a lemma against headwords. If more than one match,\n        then return the concatenated entries. For example:\n\n        >>> lll = LatinLewisLexicon()\n        >>> lll.lookup(\"clemens\")[:50]\n        'cl\u0113m\u0113ns entis (abl. -t\u012b; rarely -te, L.), adj. wit'\n        >>> lll.lookup(\"omnia\")\n        ''\n        >>> lll.lookup(\".\")\n        ''\n        >>> lll.lookup(\"123\")\n        ''\n        >>> lll.lookup(\"175.\")\n        ''\n        \"\"\"\n        if not self.entries:\n            raise CLTKException(\n                \"No lexicon entries found in the .yaml file. This should never happen.\"\n            )\n\n        if regex.match(r\"^[0-9\\.\\?,\\:;\\!\\<\\>\\-]*$\", lemma) is not None:\n            return \"\"\n\n        lemma = lemma.lower()\n\n        keys = self.entries.keys()\n        matches = [key for key in keys if regex.match(rf\"^{lemma}[0-9]?$\", key)]\n        n_matches = len(matches)\n        if n_matches > 1:\n            return \"\\n\".join([self.entries[key] for key in matches])\n        elif n_matches == 1:\n            return self.entries[matches[0]]\n        else:\n            return \"\"\n\n    def _load_entries(self):\n        \"\"\"Read the yaml file of the lexion.\"\"\"\n        with open(self.lewis_yaml_fp) as file_open:\n            entries = yaml.load(file_open, Loader=yaml.Loader)\n        return entries\n", "path": "src/cltk/lexicon/lat.py"}], "after_files": [{"content": "\"\"\"Code for querying Latin language dictionaries/lexicons.\"\"\"\n\nimport regex\nimport yaml\n\nfrom cltk.core.exceptions import CLTKException\nfrom cltk.data.fetch import FetchCorpus\nfrom cltk.utils.file_operations import make_cltk_path\nfrom cltk.utils.utils import query_yes_no\n\n__author__ = [\"Cl\u00e9ment Besnier <clem@clementbesnier.fr>\"]\n\n\nclass LatinLewisLexicon:\n    \"\"\"Access a digital form of Charlton T. Lewis's *An Elementary Latin Dictionary* (1890).\"\"\"\n\n    def __init__(self, interactive: bool = True):\n        self.interactive = interactive\n        self.lewis_yaml_fp = make_cltk_path(\n            \"lat\", \"lexicon\", \"cltk_lat_lewis_elementary_lexicon\", \"lewis.yaml\"\n        )\n        try:\n            self.entries = self._load_entries()\n        except FileNotFoundError:\n            if self.interactive:\n                dl_msg = f\"This part of the CLTK depends upon Lewis's *An Elementary Latin Dictionary* (1890).\"\n                print(dl_msg)\n                dl_question = \"Do you want to download this?\"\n                do_download = query_yes_no(question=dl_question)\n            else:\n                do_download = True\n            if do_download:\n                fetch_corpus = FetchCorpus(language=\"lat\")\n                fetch_corpus.import_corpus(\n                    corpus_name=\"cltk_lat_lewis_elementary_lexicon\"\n                )\n            else:\n                raise CLTKException(\n                    f\"File '{self.lewis_yaml_fp}' is not found. It is required for this class.\"\n                )\n            self.entries = self._load_entries()\n\n    def lookup(self, lemma: str) -> str:\n        \"\"\"Perform match of a lemma against headwords. If more than one match,\n        then return the concatenated entries. For example:\n\n        >>> lll = LatinLewisLexicon()\n        >>> lll.lookup(\"clemens\")[:50]\n        'cl\u0113m\u0113ns entis (abl. -t\u012b; rarely -te, L.), adj. wit'\n        >>> all(word in lll.lookup(\"levis\") for word in [\"levis\",\"l\u0113vis\"]) # Test for concatenated entries\n        True\n        >>> lll.lookup(\"omnia\")\n        ''\n        >>> lll.lookup(\".\")\n        ''\n        >>> lll.lookup(\"123\")\n        ''\n        >>> lll.lookup(\"175.\")\n        ''\n        >>> lll.lookup(\"(\") # Test for regex special character\n        ''\n        \"\"\"\n        if not self.entries:\n            raise CLTKException(\n                \"No lexicon entries found in the .yaml file. This should never happen.\"\n            )\n\n        if regex.match(r\"^[0-9\\.\\?,\\:;\\!\\<\\>\\-]*$\", lemma) is not None:\n            return \"\"\n\n        lemma = regex.escape(lemma.lower())\n\n        keys = self.entries.keys()\n        matches = [key for key in keys if regex.match(rf\"^{lemma}[0-9]?$\", key)]\n        n_matches = len(matches)\n        if n_matches > 1:\n            return \"\\n\".join([self.entries[key] for key in matches])\n        elif n_matches == 1:\n            return self.entries[matches[0]]\n        else:\n            return \"\"\n\n    def _load_entries(self):\n        \"\"\"Read the yaml file of the lexion.\"\"\"\n        with open(self.lewis_yaml_fp) as file_open:\n            entries = yaml.load(file_open, Loader=yaml.Loader)\n        return entries\n", "path": "src/cltk/lexicon/lat.py"}]}