docs: function find_tokens(string, punctuation, abbreviations, replace, linebreak) {
    linebreak     = def(linebreak, /n{2,}/g);
    punctuation   = def(punctuation, PUNCTUATION).replace(/\./g, "").split("");
    abbreviations = def(abbreviations, ABBREVIATIONS);
    replace       = def(replace, REPLACEMENTS);
  
    // Handle replacements (contractions)
    Object.keys(replace).forEach(function (r) {
      string = string.replace(new RegExp(r, "g"), replace[r]);
    });
  
    // Handle Unicode quotes.
    string = string.replace(new RegExp("“", "g"), " “ ");
    string = string.replace(new RegExp("”", "g"), " ” ");
    string = string.replace(new RegExp("‘", "g"), " ‘ ");
    string = string.replace(new RegExp("’", "g"), " ’ ");
  
  
    // Collapse whitespace.
    string = string.replace(new RegExp("\r\n", "g"), "\n");
    string = string.replace(new RegExp(linebreak), " " + EOS + " ");
    string = string.replace(new RegExp(/\s+/g), " ");
    var tokens = [];
  
    // Start parsing the tokens
    (string + " ").split(RE_TOKEN).forEach(function (t) {
  
      // Ignore ''
      if (t.length > 0) {
        var tail = [];
  
        // Handle punctuation marks: tokens will possibly have leading or trailing punctuation.
        // Also handles for example ("good:-)" -> ["good", ":-)"]
        while (startsWithAny(t, punctuation) && (! _str.include(replace, t))) {
          // Split leading punctuation.
          if (startsWithAny(t, punctuation)) {
            tokens.push(t[0]);
            t = t.slice(1);
          }
        }
        while (endsWithAny(t, punctuation.concat(["."])) && (! _str.include(replace, t))) {
          // Split trailing punctuation and make token of it by pushing onto tail.
          if (endsWithAny(t, punctuation)) {
            tail.push(t[t.length-1]);
            t = t.slice(0, t.length-1);
          }
  
          // Split ellipsis (...) before splitting period.
          if (_str.endsWith(t, "...")) {
            tail.push("...");
            t = _str.rstrip(t.slice(0, t.length-3), ".");
          }
  
          // Split period (if not an abbreviation).
          if (_str.endsWith(t, ".")) {
            if (_.include(abbreviations, t) ||
                RE_ABBR1.test(t) ||
                RE_ABBR2.test(t) ||
                RE_ABBR3.test(t)) {
              break;
  
            // Single period encountered at the end, split off
            } else {
              tail.push(t[t.length-1]);
              t = t.slice(0, t.length-1);
            }
          }
        }
  
        // After parsing all trailing punctuations, push remaining word as token
        if (t !== "") {
          tokens.push(t);
        }
        // And add the trailing punctuation as token to.
        tokens = tokens.concat(tail.reverse());
      }
    });
  
    // Handle sentence breaks (periods, quotes, parenthesis).
    var sentences = [[]];
    var i = 0;
    var j = 0;
    while (j < tokens.length) {
      // If end of sentence token
      if (_.include(["...", ".", "!", "?", EOS], tokens[j])) {
        // Collapse mutliple eos tokens + handle quote text " "
        while (j < tokens.length &&
               _.include(["'", "\"", "”", "’", "...", ".", "!", "?", ")", EOS], tokens[j])) {
          if (_.include(["'", "\""], tokens[j]) &&
              count(sentences[sentences.length-1], tokens[j]) % 2 === 0) {
            break;
          }
          j++;
        }
  
        // Push all tokens up to end of sentence onto the last sentence entry
        for (var k = i; k<j; k++) {
          if (tokens[k] !== EOS) {
            sentences[sentences.length-1] = sentences[sentences.length-1].concat(tokens[k]);
          }
        }
  
        // Start new sentence entry
        sentences.push([]);
        i = j;
      }
      j++;
    }
  
    // Push remaining tokens onto last sentence
    for (var l = i; l < j; l++) {
      sentences[sentences.length-1] = sentences[sentences.length-1].concat(tokens[l]);
    }
  
    // Join each sentence with white-spaces and filter out zero-length sentences. 
    sentences = _.compact(sentences.map(function (s) {
      return ((s.length > 0) ? s.join(" ") : false);
    }));
  
    // Join white-spaced sarcasm
    sentences = sentences.map(function (s) {
      return s.replace(RE_SARCASM, "(!)");
    });
  
    // Join white-spaced emoticons.
    sentences = sentences.map(function (s) {
      return s.replace(RE_EMOTICONS, function (a) {
        return a.replace(/\ /g, "");
      });
    });
  
    return sentences;
  }