docstr: Attempts to crack Soundex by generating all possible combinations.
docstr_tok: ["Attempts","to","crack","Soundex","by","generating","all","possible","combinations","."]
code: def attemptCrack(self, ctext: str) -> List[CrackResult]:
      """
      Attempts to crack Soundex by generating all possible combinations.
      """
      logging.debug("Attempting Soundex cracker")
      word_list = []
      sentences = []
      result = []
  
      # Convert to uppercase and replace delimiters and whitespace with nothing
      ctext = re.sub(r"[,;:\-\s]", "", ctext.upper())
  
      # Make sure ctext contains only A-Z and 0-9
      if bool(re.search(r"[^A-Z0-9]", ctext)) is True:
          logging.debug(
              "Failed to crack soundex due to non soundex character(s)"
          )
          return None
  
      # Make sure ctext is divisible by 4
      ctext_len = len(ctext)
      if ctext_len % 4:
          logging.debug(
              f"Failed to decode Soundex because length must be a multiple of 4, not '{ctext_len}'"
          )
          return None
  
      # Split ctext into groups of 4
      ctext = " ".join(
          ctext[i : i + 4] for i in range(0, len(ctext), 4)
      )
      ctext_split = ctext.split(" ")
      soundex_keys = self.SOUNDEX_DICT.keys()
  
      # Find all words that correspond to each given soundex code
      for code in ctext_split:
          if code in soundex_keys:
              word_list.append(self.SOUNDEX_DICT[code])
  
      logging.info(
          f"Possible words for given encoded text: {word_list}"
      )
  
      # Find all possible sentences
      self.getSentenceCombo(
          word_list,
          sentences,
          self.frequency_dict,
          self.sentence_freq,
          self.word_freq,
      )
  
      sorted_sentences = self.sortlistwithdict(
          sentences, self.frequency_dict
      )
  
      for sentence in sorted_sentences:
          result.append(CrackResult(value=sentence))
  
      logging.debug(f"Soundex cracker - Returning results: {result}")
      return result
  
file_path: Ciphey/ciphey/basemods/Crackers/soundex.py
imports: import re
  from typing import Dict, List, Optional
  import logging
  from rich.logging import RichHandler
  from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, Translation, registry
label_desc: Use image node_id 3 for calling the Soundex obj's underlying member method code with example usage: obj.attemptCrack(ctext) and returns: result, None, None