add_cleaned_column_ <- function(DT, cols, whitespace="both", inside_parens=TRUE, parens=TRUE, trim=TRUE, tolower=TRUE, toupper=FALSE, duplicate_whitespace=TRUE) {

  ws_both <- identical(whitespace, "both")

  newCol <- paste0(cols, "_cleaned")

  if (ws_both) {
    whitespace <- FALSE
    # newCol2 <- copy(newCol)
    # newCol %<>% paste0("_withws")
    newCol2 <- paste0(newCol, "_nows")
  } else { 
    whitespace <- isTRUE(whitespace)
  }

  DT[, (newCol) := lapply(.SD, clean_names_to_simple_alpha, whitespace=whitespace, inside_parens=inside_parens, parens=parens, trim=trim, tolower=tolower, toupper=toupper, duplicate_whitespace=duplicate_whitespace), .SDcols=cols]

  if (ws_both)
    DT[, (newCol2) := lapply(.SD, removeText, pattern="\\s+"), .SDcols=newCol]

  return(invisible(DT))
}

clean_names_to_simple_alpha <- function(x
  , words_to_rem=c("the", "a", "y", "an", "inc", "llc", "ltd", "al", "el", "la", "lo", "le", if(punctuation) "and")
  , and_clean=!("and" %in% words_to_rem)
  , whitespace=FALSE
  , duplicate_whitespace=TRUE
  , inside_parens=parens
  , parens=TRUE
  , punctuation=TRUE
  , trim=TRUE
  , non_ascii_letters=TRUE
  , comma_force_trailing_space=(punctuation && !whitespace) ## if preserving whitespace but removing punctuations
  ## If we are getting rid of all punctuation and duplicate whitespace, optionally coerce punctuation to space (The only time this will be an issue is for someone's possesive)
  ## Note that this has a side effect of converting any non-space whitespace before or after a punctuation to a simple space. (ie \t ~> " ")
  , force_space_around_all_punctuation=(punctuation && duplicate_whitespace)
  , tolower=lower
  , toupper=upper
  , lower=TRUE
  , upper=FALSE
  ) {

    if (!missing("lower"))
      message("'lower' has been DEPRECATED from clean_names_to_simple_alpha()  --  use 'tolower'")
    if (!missing("upper"))
      message("'upper' has been DEPRECATED from clean_names_to_simple_alpha()  --  use 'tolower'")

    if (toupper & tolower) {
      warning("only one of 'tolower' and 'touppper' should be TRUE.  using 'toupper'")
      tolower <- FALSE
    }

    ## force_space_around_all_punctuation only makes sense in combination with other settings
    if (force_space_around_all_punctuation) {
      if (!punctuation)
        warning ("having 'force_space_around_all_punctuation' be TRUE when 'punctuation' is FALSE will not give the intended results\n\nThe reason being that the 'puncs' used in clean_names_to_simple_alpha() will be overwritten to c() when 'punctuation' is FALSE. If this is a conflict, modify the code")
      if (!duplicate_whitespace)
        warning ("having 'force_space_around_all_punctuation' be TRUE but 'duplicate_whitespace' be FALSE will introduce extra whitespace around each punctuation")
      if (whitespace) {
        warning ("having 'force_space_around_all_punctuation' be TRUE but 'whitespace' also be TRUE has no effect, since any whitespace introduced will subsequently be removed.\n force_space_around_all_punctuation will be ignored")
        force_space_around_all_punctuation <- FALSE
      }
    }

    ## FORCE ALL ARGUMENTS, Since argument errors downstream can waste a lot of time
    force(words_to_rem); force(and_clean); force(whitespace); force(duplicate_whitespace); force(inside_parens); force(parens); force(punctuation); force(trim); force(non_ascii_letters); force(comma_force_trailing_space); force(tolower); force(toupper);


    ## change words_to_rem to match the final x
    if (toupper)
      words_to_rem %<>% toupper()
    if (tolower)
      words_to_rem %<>% tolower()

    ## remove 
    if (whitespace) {
      if (!missing(duplicate_whitespace) && duplicate_whitespace)
        warning("Setting 'duplicate_whitespace' to TRUE is redundant when 'whitespace' is TRUE")
      duplicate_whitespace <- FALSE
      trim <- FALSE
    }

    ## The pattern for words inside parenthesis
    pat.inside_parens <- "\\(.*\\)"

    puncs <- c("‘","!","\"","#","%","&","'","*","+",",","-",".","/",":",";","<","=",">","?","@","[","\\","]","^","_","`","{","|","}","~","’", "´"
      ## odd characters that might be poor UTF conversion
      ,"™", "°"
      ## Currency
      , "$", "¥", "₡", "£", "€", "ƒ", "¢")

    ## clear out punctuation, in case parens are yes and punc is no.
    if (!punctuation)
      puncs <- c()

    ## Add parenthesis only if flagged AND not removing the inside of parenthesis
    if (parens && !inside_parens)
      puncs %<>% c("(",")")

    ## escape all the punctuation
    puncs %<>% unique %>% escapeRegEx()

    ## Before anything else, make sure each punctuation has exactly one space on either side
    if (force_space_around_all_punctuation) {
      ## remove possessives
      if (punctuation)
        x %<>% gsub("(\\w)'(s\\b)", "\\1\\2", .)
      pat.pad_punc <- sprintf("(.)\\s?%s\\s?(.)", regOr(puncs, escape=FALSE))
      repl.pad_punc <- "\\1 \\2 \\3"
      x %<>% gsub(pat.pad_punc, repl.pad_punc, x=.)
    }


    ## Combine all the items to simply remove
    pat.to_remove <- c(puncs
                      , if (whitespace) "\\s"
                      , if (inside_parens && parens) pat.inside_parens
                      , if (trim) c("^\\s+", "\\s+$")
                      ) %>% regOr(escape=FALSE, asterisk=NULL)

    ## letters for ascii conversion
    dict.letter_cleanup <- getDict("letter_cleanup")
    non_ascii <- names(dict.letter_cleanup)
    ascii <- as.character(unname(dict.letter_cleanup))

    x %>% {if (and_clean) cleanAndWords(.) else .} %>%
          {if (comma_force_trailing_space) gsub(",\\s*", ", ", .) else .} %>%
          {if (length(words_to_rem)) removeWord(words=words_to_rem, ., single_letter_special_treatment=TRUE) else .} %>% 
          {if (inside_parens && !parens) gsub(pat.inside_parens, "()", .) else .} %>%
          {if (non_ascii_letters) chartr(old=non_ascii, new=ascii, x=.) else .} %>%
          {if (nchar(pat.to_remove)) removeText(pat.to_remove, .) else .} %>% 
          {if (duplicate_whitespace) gsub("\\s+", " ", .) else .} %>%
          {if (tolower) tolower(.) else .} %>%
          {if (toupper) toupper(.) else .}
}