Получить массив всех возможных комбинаций l33t в Javascript - PullRequest
0 голосов
/ 17 января 2019

У меня есть строка, в которой я хотел бы получить все возможные комбинации replace -ment, используя следующие замены:

var equiv = {
  "a": "4",
  "b": "8",
  "e": "3",
  "i": "1",
  "l": "1",
  "o": "0",
  "t": "7"
}

Я хотел бы определить функцию String.prototype, что-то вроде:

String.prototype.l33tCombonations = function()
{
    var toReturn = [];

    for (var i in equiv)
    {
        // this.???
        // toReturn.push(this???)
    }

    return toReturn;
}

Так что я мог бы подать что-то вроде "tomato".l33tCombinations() и вернуться:

["tomato", "t0mato", "t0mat0", "tomat0", "toma7o", "t0ma7o", "t0m470", ...].

Порядок не важен. Мысли? * * 1013

Ответы [ 5 ]

0 голосов
/ 17 января 2019

Я подходил к этому рекурсивно, на каждой итерации рекурсии анализируется новый символ строки, если у этого символа есть замена, то и character, и replacement объединяются со всемипредыдущие результаты создают новый набор результатов, в противном случае только character объединяется со всеми предыдущими результатами.Обратите внимание, что я злоупотребляю оператором распространения для этого подхода.

var equiv = {a: "4", b: "8", e: "3", i: "1", l: "1", o: "0", t: "7"};

const genComb = (str, arr) =>
{
    if (!str) return arr; // Finish condition.
    let c = str[0];       // New char to be appended.
    let r = equiv[c];     // New char replacement.

    return genComb(
        str.slice(1),
        [...arr.map(e => e + c), ...(r ? arr.map(e => e + r) : [])]
    );
};

String.prototype.l33tCombinations = function()
{
   return genComb(this, [""], 0);
}

console.log("tomato".l33tCombinations());
0 голосов
/ 17 января 2019

Вы можете взять декартово произведение для генерации искомых значений.

function leet(string) {
    const
        cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
        code = { a: "4", b: "8", e: "3", i: "1", l: "1", o: "0", t: "7" };

    return Array
         .from(string, c => c in code ? [c, code[c]] : [c])
         .reduce(cartesian)
         .map(a => a.join(''));
}

console.log(leet('tomatoe'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 17 января 2019

Я думаю, что это может дать желаемый результат! Проходите по каждой букве и каждый раз, когда будет найдена новая замена, добавляйте новое слово в toReturn и обязательно ищите каждое новое слово!

var equiv = {
  "a": "4",
  "b": "8",
  "e": "3",
  "i": "1",
  "l": "1",
  "o": "0",
  "t": "7"
}

String.prototype.l33tCombinations = function() {
  var toReturn = [this.toLowerCase()];

  for (let i = 0; i < toReturn.length; i++) {
  
    for (let j = 0; j < toReturn[i].length; j++) {
      if (equiv[toReturn[i][j]]) {
       let newWord = toReturn[i].split('');
       newWord[j] = equiv[newWord[j]];
       let newWordJoined = newWord.join('');
       if (!toReturn.includes(newWordJoined))
        toReturn.push(newWordJoined);
      }
    }
 
  }

  return toReturn;
}

console.log('tomato'.l33tCombinations());
0 голосов
/ 17 января 2019

Вы можете сделать что-то подобное, используя reduce

Идея состоит в том, чтобы перебрать каждый символ и добавить каждую комбинацию в аккумулятор. Если вы встретите персонажа, который не является частью equiv, просто добавьте его к каждому элементу в аккумуляторе. Если персонаж действительно существует в equiv, продублируйте все предыдущие комбинации и добавьте еще один набор комбинаций с equiv[<character>]

const equiv = {
  "a": "4",
  "b": "8",
  "e": "3",
  "i": "1",
  "l": "1",
  "o": "0",
  "t": "7"
}

const input = "tomato";

const output = [...input].reduce((acc, c, i) => {
  const r = equiv[c];
  
  if (i === 0) {
    return r ? [c, r] : [c];
  }

  const updated = acc.map(a => a + c);
  const newItems = r ? acc.map(a => a + r) : [];
  
  return [...updated, ...newItems]
}, [])

console.log(output)
0 голосов
/ 17 января 2019

Я бы использовал рекурсивный подход, который перебирает строку char на char:

const toL33t = { "a": "4", "b": "8",  "e": "3",  "i": "1", "l": "1",  "o": "0",  "t": "7" };

function* l33t(string, previous = "") {
  const char = string[0];
  // Base case: no chars left, yield previous combinations
  if(!char) {
    yield previous;
    return;
  }
  // Recursive case: Char does not get l33t3d
  yield* l33t(string.slice(1), previous + char);
  // Recursive case: Char gets l33t3d
  if(toL33t[char])
    yield* l33t(string.slice(1), previous + toL33t[char]);
}

console.log(...l33t("tomato"));

Если вам действительно нужен прототип, это также возможно3, но я бы не рекомендовал:

 String.prototype.l33t = function() {
   return [...l33t(this)];
 };

 console.log("stuff".l33t());
...