6
\$\begingroup\$

Please review the code quality of this l33t Speak translator. Improvement suggestions are welcome. Here it is - http://jsbin.com/IHoFuQE/1

(function() {
  "use strict";

  // http://en.wikipedia.org/wiki/Leet
  // http://www.catb.org/jargon/html/crackers.html

  var alphabets = { // common
    "a": "4",
    "b": "8",
    "e": "3",
    "f": "ph",
    "g": "6", // or 9
    "i": "1", // or |
    "o": "0",
    "s": "5",
    "t": "7" // or +
  },
    alphabets2 = { // less common
      "c": "(", // or k or |< or /<
      "d": "<|",
      "h": "|-|",
      "k": "|<", // or /<
      "l": "|", // or 1
      "m": "|\\/|",
      "n": "|\\|",
      "p": "|2",
      "u": "|_|",
      "v": "/", // or \/
      "w": "//", // or \/\/
      "x": "><",
      "y": "'/"
    };

  var words = {
    "am": "m",
    "are": "r",
    "at": "@",
    "thanks": "thx",
    "your": "ur",

    "cool": "kewl",
    "defeated": "pwned",
    "dude": "d00d",
    "fear": "ph33r", // or ph34r
    "fool": "f00",
    "freak": "phreak",
    "hacker": "h4x0r",
    "lamer": "l4m3r",
    "mad": "m4d",
    "newbie": "n00b",
    "own": "pwn",
    "phone": "fone",
    "porn": "pr0n", // or n0rp
    "rocks": "roxxorz",
    "skill": "sk1llz",
    "sucks": "sux0r",
    "the": "t3h",
    "uber": "ub3r", // or |_|83r
    "yay": "w00t",
    "yo": "j0",
    "you": "j00" // or U
  };

  var elite = document.getElementById("elite"),
    leet = document.getElementById("leet"),
    randomcase = document.getElementById("randomcase"),
    adv = document.getElementById("adv"),
    btn = document.getElementById("btn");

  function changeLetters(text) { // change letters
    text = text || elite.value.toLowerCase();
    for (var i = 0; i < text.length; i++) {
      var alphabet = adv.checked ? alphabets[text[i]] || alphabets2[text[i]] : alphabets[text[i]];
      if (alphabet) {
        text = text.replace(text[i], alphabet);
      }
    }
    return text;
  }

  function changeWords() { // change special words and return text
    return changeLetters().replace(
      /\w+/g,
      function(word) {
        return words[word] ? words[word] : word;
      }
    );
  }

  function randomizeCase() { // RANdOMiZE CAsE
    var text = changeWords();
    for (var i = 0; i < text.length; i++) {
      if (Math.random() > 0.5) {
        text = text.replace(text[i], text[i].toUpperCase());
      } // else keep lower case
    }
    return text;
  }

  (function() { // l33t the words object
    for (var word in words) {
      if (words.hasOwnProperty(word)) {
        words[changeLetters(word)] = words[word];
        delete words[word];
      }
    }
  }());

  function tol33t() {
    leet.value = randomcase.checked ? randomizeCase() : changeWords();
  }

  elite.addEventListener("input", tol33t);
  btn.addEventListener("click", tol33t);
}());
\$\endgroup\$
5
\$\begingroup\$

To start with, I'd like to give you credit for using "use strict" and limiting the scope of variables using functions.

Your tol33t() function is weird to me. If the randomcase button is checked, you call randomizeCase() with no arguments. What are you randomizing the case of? It turns out that randomizeCase() calls changeWords(), so it turns out that the two code branches have something in common after all. That wasn't apparent from looking at tol33t().

There should be clearer separation responsibility between the DOM-interaction and text-translation layers of code. The text translation code should reside in pure functions (whose results depend solely on their parameters) that you could call from the JavaScript console or from a unit testing engine. That separation of concerns could be accomplished with:

function onTranslateButtonClicked() {
    var l33tText = toL33t(elite.value, adv.checked);
    if (randomcase.checked) l33tText = randomizeCase(l33tText);
    leet.value = l33tText;
}

Your "l33t the words object" initialization routine lays a trap for anyone trying to read the code. When code in changeWords() refers to the words associative array, one would reasonably think that it's using the definition above (i.e., words = { "am": "m", … }) instead of the munged version (words = { "4m": "m" }). Better to make that munging explicit when you define words (and do so by returning a copy rather than mutating the dictionary as you iterate):

var words = l33tKeys({
    "am": "m",
    …
});

function l33tKeys(dict) {
    var l33tDict = {};
    for (var word in dict) {
        l33tDict[changeWord(word)] = dict[word];
    }
    return l33tDict;
}

I would write changeLetters() as:

 // letterSubsts may be alphabet or alphabet2
function changeLetters(text, letterSubsts) {
    return text.toLowerCase().replace(/[a-z]/g, function(letter) {
        return letterSubsts[letter] || letter;
    });
}

… which is actually analogous to your implementation of changeWords().

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer. But I'm having problem connecting all these. So would you please modify my jsBin. \$\endgroup\$ – udb Jan 16 '14 at 12:47
  • \$\begingroup\$ finally I've implemented your changes, please see - jsbin.com/AREZoCig/2/edit?js,output \$\endgroup\$ – udb Jan 17 '14 at 7:46
  • \$\begingroup\$ But the advanced leet wont work if I use your changeLetters() \$\endgroup\$ – udb Jan 17 '14 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.