docstr: Attempts to decode both variants of the Baconian cipher.
code: def attemptCrack(self, ctext: str) -> List[CrackResult]:
      """
      Attempts to decode both variants of the Baconian cipher.
      """
      logging.debug("Attempting Baconian cracker")
      candidates = []
      result = []
      ctext_decoded = ""
      ctext_decoded2 = ""
  
      # Convert to uppercase and replace delimiters and whitespace with nothing
      ctext = re.sub(r"[,;:\-\s]", "", ctext.upper())
  
      # Make sure ctext only contains A and B
      if bool(re.search(r"[^AB]", ctext)) is True:
          logging.debug(
              "Failed to crack baconian due to non baconian character(s)"
          )
          return None
  
      # Make sure ctext is divisible by 5
      ctext_len = len(ctext)
      if ctext_len % 5:
          logging.debug(
              f"Failed to decode Baconian because length must be a multiple of 5, not '{ctext_len}'"
          )
          return None
  
      # Split ctext into groups of 5
      ctext = " ".join(
          ctext[i : i + 5] for i in range(0, len(ctext), 5)
      )
      ctext_split = ctext.split(" ")
      baconian_keys = self.BACONIAN_DICT.keys()
  
      # Decode I=J and U=V variant
      for i in ctext_split:
          if i in baconian_keys:
              ctext_decoded += self.BACONIAN_DICT[i]
  
      # Decode variant that assigns each letter a unique code
      for i in ctext_split:
          if "+" + i in baconian_keys:
              ctext_decoded2 += self.BACONIAN_DICT["+" + i]
  
      candidates.append(ctext_decoded)
      candidates.append(ctext_decoded2)
      for candidate in candidates:
          if candidate != "":
              if candidate == candidates[0]:
                  result.append(
                      CrackResult(value=candidate, key_info="I=J & U=V")
                  )
              else:
                  result.append(CrackResult(value=candidate))
      logging.debug(f"Baconian cracker - Returning results: {result}")
      return result
  
file_path: Ciphey/ciphey/basemods/Crackers/baconian.py
imports: import re
  from typing import Dict, List, Optional
  from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, Translation, registry
  import logging
  from rich.logging import RichHandler
label_desc: Use image node_id 3 for calling the Baconian obj's underlying member method code with example usage: obj.attemptCrack(ctext) and returns: result, None, None