功能竞赛

时间:2011-02-11 01:23:10

标签: javascript code-golf scramble

请记住,目标上的消息如何说明:

  

Aoccdrnig对Cmabrigde Uinervtisy的一个关键人物来说,它并不是一个人,而是在一个人的战斗中,对于这个问题而言,这是一个很好的问题,而且这个问题很明显,而且还有一个问题。 rset可以是一个toatl mses,你可以坐下来讨论它的问题。 Tihs是bcuseae the huamn mnid deos不是由istlef竞选ervey lteter,而是作为一个wlohe。

无论如何,我正在努力创建一个能够完成整个页面的功能。这个功能有一些规则。

  1. 少于4个字符。
  2. 非字母数字字符不算作单词的一部分。
  3. 带连字符的单词实际上是两个单词
  4. 如果长度> gt = = 4(不能像原版)
  5. ,则必须出现乱码
  6. 第一个和最后一个字符保持不变,只有中间字符变得乱码(感谢Hersheezy)
  7. 文本应始终是随机的,并在每次运行时产生独特的杂物
  8. 纯javascript并在所有文本节点上迭代
  9. 最甜蜜的代码获胜。
  10. 无论如何,它实现起来似乎很简单,如何开始竞赛,看看谁能够制作最干净,最清晰的代码来完成这项任务。在没有我的代码识别的情况下随意借用(我有权)

    如果我错过任何内容,请在评论中添加。无论如何,我非常狡猾地工作,这是我展示我不太平庸的工作

    DEMO

    var i, j, words, textNodes, punct = /[^a-zA-Z0-9]/;
    
    Array.prototype.shuffle = function() {
        for (var i = 0; i < this.length; i++) {
            var j = i;
            while (j == i) {
                j = Math.floor(Math.random() * this.length);
            }
            var tmp = this[i];
            this[i] = this[j];
            this[j] = tmp;
        }
        return this;
    };
    
    String.prototype.shuffle = function() {
        return this.split('').shuffle().join('');
    };
    
    function transverse(element, array) {
        if (!array) array = [];
        if (element.nodeType === 3) {
            array.push(element);
        } else {
            for (var i = 0; i < element.childNodes.length; i++) {
                transverse(element.childNodes[i], array);
            }
        }
        return array;
    }
    
    function garble(str) {
        if (!str) return '';
        str = str.trim();
        if (/-/.test(str)) {
            str = str.split('-');
            for (var i = 0; i < str.length; i++) {
                str[i] = garble(str[i]);
            }
            return str.join('-')
        }
        if (punct.test(str.charAt(0))) {
            return str.charAt(0) + garble(str.slice(1));
        }
        if (punct.test(str.charAt(str.length - 1))) {
            return garble(str.slice(0, -1)) + str.charAt(str.length - 1);
        }
        if (str.length < 4) return str;
        if (str.length === 4) return str.charAt(0) + str.charAt(2) + str.charAt(1) + str.charAt(3)
        return str.charAt(0) + str.substr(1, str.length - 2).shuffle() +
            str.charAt(str.length - 1);
    }
    
    
    window.onload = function() {
        textNodes = transverse(document.documentElement);
        for (i = 0; i < textNodes.length; i++) {
            words = textNodes[i].data.split(' ');
            for (j = 0; j < words.length; j++) {
                words[j] = garble(words[j]);
            }
            textNodes[i].data = words.join(' ');
        }
    };
    

4 个答案:

答案 0 :(得分:9)

更新(最新):不要认为它可以变得更小.. DEMO
最新压缩(332):

var e=document.body.getElementsByTagName('*'),j,i,l,x,t,b;for(i=0;e[i];i++)for(j=0;b=e[i].childNodes[j];j++)if(b.nodeType==3)b.data=b.data.replace(/\w{4,}/g,function(w){if(/(^.)(\1)+$/.test(x=w.substring(1,l=w.length-1)))return w;t=w;while(t==w)t=w[0]+x.split('').sort(function(){return 0.5-Math.random()}).join('')+w[l];return t}); 

代码:

var e = document.body.getElementsByTagName('*'),
    j, i, l, x, t, b;
for (i = 0; e[i]; i++)
for (j = 0; b = e[i].childNodes[j]; j++)
if (b.nodeType == 3) b.data = b.data.replace(/\w{4,}/g, function(w) {
    if (/(^.)(\1)+$/.test(x = w.substring(1, l = w.length - 1))) return w;
    t = w;
    while (t == w)
    t = w[0] + x.split('').sort(function() {
        return 0.5 - Math.random();
    }).join('') + w[l];
    return t;
});

更新甚至更小..

Even smaller version
我不知道你使用的缩放器,但这必须至少( EDIT 108)字节更小。
压缩版本(365字节):

var e=document.body.getElementsByTagName('*'),a=[],c,j,i,l,x,t,b;for(i=0;c=e[i];i++)for(j=0;b=c.childNodes[j];j++)if(b.nodeType==3){b.data=b.data.replace(/\b[a-z0-9]{4,}\b/gi,function(w){if(/(^.)(\1)+$/.test(x=w.substring(1,l=w.length-1)))return w;t=w;while(t==w)t=w[0]+x.split('').sort(function(){return Math.floor(Math.random()*2)?1:-1}).join('')+w[l];return t})}  

代码:

var e = document.body.getElementsByTagName('*'),
    a = [],
    c, j, i, l, x, t, b;
for (i = 0; c = e[i]; i++)
for (j = 0; b = c.childNodes[j]; j++)
if (b.nodeType == 3) {
    b.data = b.data.replace(/\b[a-z0-9]{4,}\b/gi, function(w) {
        if (/(^.)(\1)+$/.test(x = w.substring(1, l = w.length - 1))) return w;
        t = w;
        while (t == w)
        t = w[0] + x.split('').sort(function() {
            return Math.floor(Math.random() * 2) ? 1 : -1;
        }).join('') + w[l];
        return t;
    });
}

修改
 NEW RULES DEMO
代码:

var fn = function(e) {
    var ret = [],c;
    for (var i = 0; i < e.length; i++) {
        c = e[i].childNodes;
        for (var j = 0; j < c.length; j++)
            if (c[j].nodeType === 3) ret.push(c[j]);
    }
    return ret;
};
var es = fn(document.body.getElementsByTagName('*'));
for (var i = 0; i < es.length; i++) {
    var e = es[i],len,x;
    e.data = e.data.replace(/\b[a-z0-9]{4,}\b/gi, function(w) {
        if (/(^.)(\1)+$/.test(x = w.substring(1, len = w.length - 1))) return w;
        var tmp = w;
        while (tmp === w) {
            tmp = w[0] + x.split('').sort(function() {
                return Math.floor(Math.random() * 2) ? 1 : -1;
            }).join('') + w[len];
        }
        return tmp;
    });
}

这应该尊重所有规则,并保持格式和标点符号。 DEMO

//select all nodes in document and perform map on it to filter out
//non text node types, then each one of those elements is processed.
$('*').contents().map(function(i, elem) {
    if (elem.nodeType !== 3) return null;
    else return elem;
}).each(function(i, elem) {
 //call strip funciton defined down to get an object, with a word array, and
 //charecters which was stripped along with there index in the orginal string
    var str1 = '',
        tmp = strip(elem.data),
        words = tmp.words,
        sentence;
    // shuffle all words
    words = $.map(words, function(x, i) {
        return shuffle(x);
    });
    //construct raw sentence (non alphanumeric charecters)
    sentence = words.join('');
    //reinsert spaces and punctiouation 
    $.each(tmp.chars, function(i, elem) {
        sentence = sentence.substring(0, elem.index) + elem.char + sentence.substring(elem.index - 1 + elem.char.length);
    });
    //set the element text
    elem.data = sentence;
});

//shuffle funciton takes a word and shuffle the charecters between the last and the firt
function shuffle(txt) {
    //if the word is smaller than 4 charecters or it has repeated charecters in
    //its middle (i.e. loop, 'oo' cannot be shuffled!) then return it;
    if (txt.length < 4 || /(^.)(\1)+$/.test(txt.substring(1, txt.length - 1)))
        return txt;
    var str = txt.split(''),
        ret = [],
        rand, x = 0,
        tmp = txt;
    //while the txt hasn't changed in the first randomization cycle then repeated
    while (txt === tmp) {
        ret = [];
        $.each(str, function(i, c) {
            if (i === str.length - 1 || i === 0) {
                ret[i] = c;
                return;
            }
            while (true) {
                rand = Math.floor(Math.random() * (str.length - 2) + 1);
                if (!ret[rand]) {
                    ret[rand] = c;
                    break;
                }
            }
        });
        tmp = ret.join('');
    }
    return ret.join('');
}

function strip(txt) {
    var punc = /[^A-Za-z0-9]/g,
        res, nonAlphaNum = [],
        arr;
    //punc regex is all non-alphanumeric charecters which will act on the string
    //to point out unwanted charecters and store them in an array along with
    //their index
    while ((res = punc.exec(txt)) != null) {
        nonAlphaNum.push({
            index: res.index,
            char: res[0]
        });
    }
    //split into words
    arr = txt.split(/\s/);
    //remove punctiuation and other unwanted chars
    arr = $.map(arr, function(x, i) {
        return x.replace(punc, '');
    });
    return {
        words: arr,  //words array
        chars: nonAlphaNum //array of stripped charecter objects (chars, index in orginal)
    };
} 

btw很好的选择文章,WWiWieikikb !!

答案 1 :(得分:6)

更新

所以我忍不住玩了一下这个东西,看看我用尽可能少的代码操作文档的其他方法。可以说它可以缩短为在任何一种情况下工作,但是我喜欢用一些选项供用户玩。

话虽如此,以上是对上述内容和好处/失望的一些变化:


官方提交(473字节)

缩小(473字节) 1

function t(e){var r=[],w;for(w=0;w<e.length;w++){if(e[w].nodeType===3)r.push(e[w]);else if(e[w].childNodes)r=r.concat(t(e[w].childNodes));}return r;}var e,x=t(document.body.childNodes),y,z;for(y=0;y<x.length;y++){x[y].data=x[y].data.replace(/\b[a-z]{4,}\b/ig,function(w){if(w.length==4&&(/^.([a-z])\1./i).test(w))return w;e=w;while(e==w){z=w.split('');e=z[0]+(z.slice(1,z.length-1).sort(function(a,b){return(Math.random()*2)>1?1:-1;}).join(''))+z[z.length-1];}return e;});}

未缩小版本:(479字节) 1

function t(e){
  var r=[],w;
  for(w=0;w<e.length;w++){
    if(e[w].nodeType===3)r.push(e[w]);
    else if(e[w].childNodes)r=r.concat(t(e[w].childNodes));
  }
  return r;
}
var x=t(document.body.childNodes);
for(var y=0;y<x.length;y++){
  x[y].data=x[y].data.replace(/\b[a-z]{4,}\b/ig,function(w){
    if(w.length==4&&(/^.([a-z])\1./i).test(w))
      return w;
    var e=w;
    while (e==w){
      var x=w.split('');
      e=x[0]+(x.slice(1,x.length-1).sort(function(a,b){
        return(Math.random()*2)>1?1:-1;
      }).join(''))+x[x.length-1];
    }
    return e;
  });
}
  • 不使用jQuery(“纯javascript”)
  • <script src="garble.js"></script>之上添加</body>或将代码包装在onload事件中。

1 重新放置var声明会缩短它,请参阅479bytes vs 473 byes


其他版本

基本demo

// jQuery Garble
// "Basic" version
//
// Requirements:
// 1. Find all words 4+ letters long (exclude hyphens, punctuation or numbers from
//    the classification)
// 2. The words being garbled must follow:
//    a. They can not remain the same as the previous state
//    b. The first and last character must remain in-tact
// 3. The garbling must be random and produce a new result each iteration.
//
// Usage:
// $(selector).garble(options);
//
(function($){
    $.fn.extend({
        garble: function(options){
            // basic options
            var o = $.extend({
                flagChanges: false,
                changeClass: 'modified'
            },options);
            // iterate over elements
            return this.each(function(i,e){
                var txt = $(e).text();
                // locate words with 4+ letters
                $(e).html(txt.replace(/\b[a-z]{4,}\b/ig,function(w){
                    var e = w;
                    // make sure we get an altered word back
                    while (e==w){
                        var x = w.split('');
                        e = x[0]+(x.slice(1,x.length-1).sort(function(y,z){
                            return (Math.random()*2)>1?1:-1; // randomize
                        }).join(''))+x[x.length-1];
                    }
                    return (o.flagChanges?'<span class="'+o.changeClass+'">'+e+'</span>':e);
                }));
            });
        }
    });
})(jQuery);

赞成

  1. 非常苗条和修剪
  2. 允许您修改已修改单词的选项(使用默认的“已修改”类或您选择的类包装跨度中的每个更改)。
  3. 缺点

    1. 不能使用嵌套元素(这意味着你必须在DOM树中选择尽可能低的元素。所以,如果你只是在做没有超链接或跨度的段落,那么这是你的赢家)
    2. 如果选择器中使用了具有子项的元素,则会剥离它们的html格式(例如段落中的链接)。

    3. 修身和修剪demo

      $(function(){                                                              // on load
        $('*','body').contents().map(function(i,e){                              // grab all elements,
          return e.nodeType !== 3 ? null : e;                                    // then filter by textual elements
        }).each(function(i,e){                                                   // amd iterate through them.
          e.data = e.data.replace(/\b[a-z]{4,}\b/ig, function(w) {               // go through and find 4+ letters words
            if (w.length==4&&w.substring(1,2)==w.substring(2,3))                 // (avoid infinite loops on words that
              return w;                                                          // can't be changed [e.g. look])
            var e = w;                                                           // Store the original word for comparison, but
            while (e==w){                                                        // keep scrambling until we have a new word.
              var x = w.split('');                                               // (do so by breaking out middle letters in to array,
              e = x[0] + (x.slice(1, x.length - 1).sort(function(a,b){           // then sort those middle letters
                return (Math.random() * 2) > 1 ? 1 : -1;                         // based on a random number)
              }).join('')) + x[x.length - 1];                                    // Now, rejoin it all back together
            }
            return e;                                                            // and finally return the modified result.
          });
        });
      });
      

      功能齐全demo

      // jQuery Garble
      // "Feature Rich" version
      //
      // Requirements:
      // 1. Find all words 4+ letters long (exclude hyphens, punctuation or numbers from
      //    the classification)
      // 2. The words being garbled must follow:
      //    a. They can not remain the same as the previous state
      //    b. The first and last character must remain in-tact
      // 3. The garbling must be random and produce a new result each iteration.
      //
      // Usage:
      // $(selector).garble(options);
      //
      (function($) {
          $.fn.extend({
              garble: function(options) {
                  var o = $.extend({}, $.fn.garble.defaults, options);
      
                  // takes in a string and performs the necessary manipulation(s) on it. Use regex
                  // to only collect words greater than or equal to 4 characters long, and consider
                  // punctuation not part of the word.
                  var garbleStr = function(s,t){
                      return s.replace(/\b[a-z]{4,}\b/ig, function(w) {
                          var e = o.algorithm(w);
      
                          // if we're not performing a low-level parse and they want the changes styled,
                          // return a span with either the detault class or their custom class
                          if (t && !o.lowLevel && o.highLevel.flagChanges)
                              return '<span class="'+o.highLevel.changeClass+'">'+e+'</span>';
      
                          // just return the new word
                          return e;
                      });
                  };
      
                  // Very high-level process.
                  // Will only change the lowest node's text (so a paragraph
                  // with links, only the links will be altered)
                  var highLevel = function(i, e) {
                      // we're not at the bottom element, keep going
                      if ($(e).children().length>0){
                          return $(e).children().each(highLevel);
                      }
      
                      var t = $(e).text();
                      $(e).html(garbleStr(t,e.tagName!=='TEXTAREA'));
                  };
                  // Low level process
                  // Goes down to each individual element and changes it
                  var lowLevel = function(i, e) {
                      var d = e.data;
                      e.data = garbleStr(d);
                  };
      
                  // depending their selection, execute either or
                  if (o.lowLevel){
                      return this.find('*').contents().map(function(i, e) {
                          return (e.nodeType !== 3 ? null : e);
                      }).each(lowLevel);
                  }else{
                      return this.contents().each(highLevel);
                  }
              },
          });
      
          // Defaults
          $.fn.garble.defaults = {
              // Perform low-level modification? (Modifies all words it finds,
              // not just the one farthests down the tree)
              lowLevel: false,
      
              // when lowLevel is set to false, these options are available:
              highLevel: {
                  // wrap changes in a <span>
                  flagChanges: false,
      
                  // the class being applied to the above <span>
                  changeClass: 'modified'
              },
      
              // function used to garble the text. This will be passed each word
              // individually and should return the new word's value.
              algorithm: function(w) {
                  // if w = "hello":
                  // 1. Make an array out of the letters.
                  // 2. keep the first and last in-tact, but use .slice() to extract the middle
                  // 3. Perform the specified algorithm on the middle characters
                  // 4. return result
                  var e = w;
                  while (e==w){ // secure it gets changed
                      var x = w.split('');
                      e = x[0] + (x.slice(1, x.length - 1).sort(function(a,b){
                          return (Math.random() * 2) > 1 ? 1 : -1;
                      }).join('')) + x[x.length - 1];
                  }
                  return e;
              }
          };
      })(jQuery);
      

      赞成

      1. 灵活。这几乎适用于所有场景,尽管可以快速处理食物链底层元素或在整个<body>上调用它 - 这可以处理它。
      2. 非常可定制:
        1. 可以指定执行低级别(每个元素)更改,或者指定高级别(仅限没有子级的元素)
        2. 可以指定是否要显示更改,以及要应用的类(更改包含在具有指定类名的范围内)
        3. 可以指定用于加扰的函数(也许您只想反转单词或使用更好的方法)
      3. 缺点

        1. 稍微多一点开销,虽然它仍然很快。
        2. 可能选择太多或太过臃肿。
        3. 我相信有人会找到更多利弊

答案 2 :(得分:1)

这是我对该功能的看法。请参阅演示here

  • 它使用优秀的jquery.ba-replacetext插件来处理仅查找文本节点
  • 处理所有内部字符相等的任意长度的单词
  • 易于理解的描述性名称

完整版(1187字节):

  /* Called on document.ready */
  $(function () {
    $("body *").replaceText(/\b([A-z]{4,})\b/g, scramble_inner );
  });
  /* Scramble the inner characters of a word */
  function scramble_inner(word) {
    return word[0] 
      + force_shuffle(word.slice(1, word.length - 1))
      + word[word.length - 1];
  }
  /* Randomize characters in the string, but check to make sure
   * they're different from the original. Handle's the special
   * case where all inner characters are equal, for instance "moooo".
   */
  function force_shuffle(str) {
    if (all_chars_same(str)) return str;
    var result = str;
    while (str === result) {
      result = str.split('').sort(function() {
        return Math.floor(Math.random() * 2) ? 1 : -1;
      }).join('');
    }
    return result;
  }
  /* Check whether all characters in the string are equal, eg "ooo" */
  function all_chars_same(str) {
    for (i = 0; i < str.length; i++) {
      if (str[i] !== str[0]) {
        return false;
      }
    }
    return true;
  }

缩小版(348字节):

$(function(){$("body *").replaceText(/\b([A-z]{4,})\b/g,a)});function a(w){return w[0]+b(w.slice(1,w.length-1))+w[w.length-1]}function b(s){if(c(s))return s;var r=s;while(s===r){r=s.split('').sort(function(){return Math.floor(Math.random()*2)?1:-1}).join('')}return r}function c(s){for(i=0;i<s.length;i++){if(s[i]!==s[0]){return false}}return true}

答案 3 :(得分:0)

注意:我是通过JSLint运行的,这可能是一个坏主意。无论如何,演示是here

function shuffle(letters) {
    var i = letters.length - 2;
    while (i > 1) {
        var pos = Math.floor(Math.random() * i) + 1;
        var tmp = letters[i];
        letters[i] = letters[pos];
        letters[pos] = tmp;
        i--;
    }
}

function scramble(word) {
    if (word.slice(1, -2) == word.slice(2, -1)) {
        return word;
    }
    var letters = word.split('');
    var result = word;
    while (result == word) {
        shuffle(letters);
        result = letters.join('');
    }
    return result;
}

function process(node) {
    var data = node.data;
    if (/[a-z]{4}/i.test(data)) {
        node.data = data.replace(/[a-z]{4,}/gi, scramble);
    }
}

function traverse(element) {
    var node = element.firstChild;
    while (node) {
        if (node.nodeType == Node.ELEMENT_NODE) {
            traverse(node);
        } else if (node.nodeType == Node.TEXT_NODE) {
            process(node);
        }
        node = node.nextSibling;
    }
}

function garble() {
    traverse(document.body);
}

window.onload = garble;