【问题标题】:Translating Minecraft Color Codes into HTML将 Minecraft 颜色代码翻译成 HTML
【发布时间】:2015-05-18 20:51:10
【问题描述】:

最近,我试图将 Minecraft MOTD 转换为纯 HTML。 Minecraft MOTD 是基本文本,带有代表颜色变化的 Minecraft 颜色代码。

示例:“§d§lThe Nexus§8: §6§oO_O §a§l[MUTATION MONDAY]”

翻译:<span style='color:pink'><b>The Nexus</b></span><span style='color:gray'>:</span>...

等等...所以基本上,有颜色代码,它会改变文本的颜色,还有格式代码,它会改变文本的格式。

现在,由于 Minecraft 颜色代码没有说明颜色代码的结束位置,我不知道如何将其转换为 HTML。

我确实做到了一半,将所有颜色代码替换为</span><span style='color:newcolor'>,并将所有格式代码替换为</var><var style='text-decoration:blah'>

但这不起作用,因为当您在格式代码之前有一个颜色代码时,它会变成<span></var><var></span>

所以问题是,我该怎么做?查找颜色代码的结束位置等等。

Minecraft 的颜色代码可在此处获得:http://ess.khhq.net/mc/

由于我的代码太大,我把它发布在 JSFiddle 上。

到目前为止我的代码:https://jsfiddle.net/thwe0yek/1/(第一个很好,第二个搞砸了..)

【问题讨论】:

  • 这不是CodeGolf的问题吗?
  • 我不这么认为。但也许...
  • 向我们展示示例编码文本的其余“已翻译”标记。此外,你可以只使用标签打开,你不需要关闭标签来让它显示:浏览器会理解你的意思,它实际上应该看起来不错,只是打开,因为颜色会过度 -统治以前的,它们将立即结束。丑陋的过度嵌套标记,但在屏幕上看起来应该没问题。
  • @dandavis 您的方法有效,但我真的想要一个清晰的标记,我认为 AlfonsoGarnett 的答案是最好的。不过,谢谢您的回答,我以后可能会使用它!

标签: javascript jquery html colors minecraft


【解决方案1】:

这是一种方法。

对其工作原理的简要说明:

  • 它会在字符串中查找带有匹配它们的正则表达式的所有代码(参见parseStyle 函数的第一行)
  • 它将这些代码在字符串中的位置的索引推送到一个数组中,并用双 \x00(空字符)替换每个代码,以便处理字符串后面部分的代码重复(请参阅第一个 for 循环)。
  • 它根据一个代码的开头和另一个代码的开头将字符串拆分为多个部分,以便每个部分都可以单独设置样式,并具有自己的规则。
  • 同样在第二个循环中,字符串被发送到applyCode 函数,该函数在styleMap 的帮助下应用给定的代码(通过数组)。此函数为给定的每个字符串创建一个span 元素。如果它找到k 规则,它也会应用obfuscate 函数。
  • obfuscate 函数接受一个字符串,获取它的长度,并为字符串中的每个字符生成一个随机字符。它以一个字符一个字符的间隔执行此操作。可以通过更改replaceRand 函数中的randInt 值来修改它选择的字符范围。
  • 最后,脚本返回一个具有两个属性的对象:一个是parsed,它返回一个运行“混淆器”的DOM元素,另一个是raw,它以HTML字符串的形式返回span元素(它是只是parsed 的innerHTML)。

要使用它,只需调用mineParse(string),例如:

var result = mineParse('§6Hello');
document.body.appendChild(result.parsed);

现在支持将换行符转换为<br> 标记、§r 重置代码以及以任意顺序应用的多个代码。

不过,我确信脚本可以进一步简化。另外,我确定它有错误,你可以随意修改它。

http://jsfiddle.net/fku9gsax/12/

(function () {

    'use strict';

    var currId = 0,
        obfuscators = {},
        alreadyParsed = [],
        styleMap = {
            '§0': 'color:#000000',
            '§1': 'color:#0000AA',
            '§2': 'color:#00AA00',
            '§3': 'color:#00AAAA',
            '§4': 'color:#AA0000',
            '§5': 'color:#AA00AA',
            '§6': 'color:#FFAA00',
            '§7': 'color:#AAAAAA',
            '§8': 'color:#555555',
            '§9': 'color:#5555FF',
            '§a': 'color:#55FF55',
            '§b': 'color:#55FFFF',
            '§c': 'color:#FF5555',
            '§d': 'color:#FF55FF',
            '§e': 'color:#FFFF55',
            '§f': 'color:#FFFFFF',
            '§l': 'font-weight:bold',
            '§m': 'text-decoration:line-through',
            '§n': 'text-decoration:underline',
            '§o': 'font-style:italic'
        };

    function obfuscate(elem, string) {
        var multiMagic,
            currNode,
            listLen,
            nodeI;

        function randInt(min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }

        function replaceRand(string, i) {
            var randChar = String.fromCharCode(randInt(64, 95));
            return string.substr(0, i) + randChar + string.substr(i + 1, string.length);
        }

        function initMagic(el, str) {
            var i = 0,
                obsStr = str || el.innerHTML,
                strLen = obsStr.length;
            if(!strLen) return;
            obfuscators[currId].push(
                window.setInterval(function () {
                    if (i >= strLen) i = 0;
                    obsStr = replaceRand(obsStr, i);
                    el.innerHTML = obsStr;
                    i++;
                }, 0)
            );
        }

        if (string.indexOf('<br>') > -1) {
            elem.innerHTML = string;
            listLen = elem.childNodes.length;
            for (nodeI = 0; nodeI < listLen; nodeI++) {
                currNode = elem.childNodes[nodeI];
                if (currNode.nodeType === 3) {
                    multiMagic = document.createElement('span');
                    multiMagic.innerHTML = currNode.nodeValue;
                    elem.replaceChild(multiMagic, currNode);
                    initMagic(multiMagic);
                }
            }
        } else {
            initMagic(elem, string);
        }
    }

    function applyCode(string, codes) {
        var elem = document.createElement('span'),
            obfuscated = false;

        string = string.replace(/\x00/g, '');

        codes.forEach(function (code) {
            elem.style.cssText += styleMap[code] + ';';
            if (code === '§k') {
                obfuscate(elem, string);
                obfuscated = true;
            }
        });

        if (!obfuscated) elem.innerHTML = string;

        return elem;
    }

    function parseStyle(string) {
        var finalPre = document.createElement('pre'),
            codes = string.match(/§.{1}/g) || [],
            codesLen = codes.length,
            indexes = [],
            indexDelta,
            apply = [],
            strSlice,
            i;

        if (!obfuscators[currId]) obfuscators[currId] = [];

        string = string.replace(/\n|\\n/g, '<br>');

        for (i = 0; i < codesLen; i++) {
            indexes.push(string.indexOf(codes[i]));
            string = string.replace(codes[i], '\x00\x00');
        }

        if (indexes[0] !== 0) {
            finalPre.appendChild(applyCode(string.substring(0, indexes[0]), []));
        }

        for (i = 0; i < codesLen; i++) {
            indexDelta = indexes[i + 1] - indexes[i];
            if (indexDelta === 2) {
                while (indexDelta === 2) {
                    apply.push(codes[i]);
                    i++;
                    indexDelta = indexes[i + 1] - indexes[i];
                }
                apply.push(codes[i]);
            } else {
                apply.push(codes[i]);
            }
            if (apply.lastIndexOf('§r') > -1) {
                apply = apply.slice(apply.lastIndexOf('§r') + 1);
            }
            strSlice = string.substring(indexes[i], indexes[i + 1]);
            finalPre.appendChild(applyCode(strSlice, apply));
        }

        return finalPre;
    }

    function clearObfuscators(id) {
        obfuscators[id].forEach(function (interval) {
            clearInterval(interval);
        });
        alreadyParsed[id] = [];
        obfuscators[id] = [];
    }

    window.mineParse = function initParser(input) {
        var parsed,
            i = currId;
        if (i > 0) {
            while (i--) {
                if (alreadyParsed[i].nodeType) {
                    if (!document.contains(alreadyParsed[i])) {
                        clearObfuscators(i);
                    }
                }
            }
        }
        parsed = parseStyle(input);
        alreadyParsed.push(parsed);
        currId++;
        return {
            parsed: parsed,
            raw: parsed.innerHTML
        };
    };

}());
@media (max-width: 850px) {
   
   div#inBetween {
        width: 100%;
        box-sizing: border-box;
        padding: 0.05em;
    }
    #inBetween:before {
        display: inline-block;
        font-family:'FontAwesome';
        content:"\f107";
        animation: bounceDown 2s infinite;
    }
}
@media (min-width: 850px) {
    #inBetween:before {
        display: inline-block;
        font-family:'FontAwesome';
        content:"\f105";
        animation: bounceRight 2s infinite;
    }
}
html, body {
    height: 100%;
    width:  100%;
    margin: 0;
    padding: 0;
}
button::-moz-focus-inner {
    border: 0;
}
body {
    text-align: center;
    background: #050A0E;
    font-family:'Open Sans', sans-serif;
    overflow-x: hidden;
}
#mainContainer {
  padding:  5em 0 5em 0;
}
h1 {
    font-weight: bold;
    color: #5EB4E7;
    text-shadow: 0 0 50px #5EB4E7;
    padding: 1em;
    margin:  0;
    animation: fadeIn 2s ease-in-out;
}
#inputContainer, #outputContainer {
    display: inline-block;
    padding: 1em;
    width: 20em;
    height: 21em;
    background: #152E3D;
    box-shadow: 0 0 4px #5EB4E7;
    vertical-align: middle;
    animation: scaleIn 1s ease-in-out;
}
#inBetween {
    display: inline-block;
    vertical-align: middle;
    color: #5EB4E7;
    font-size: 4em;
    padding: 0.5em;
    animation: scaleIn 1s ease-in-out;
}
#outputContainer {
    display: inline-block;
    padding: 1em;
    vertical-align: top;
    border-radius: 0 5px 5px 0;
}
#inputContainer {
    border-radius: 5px 0 0 5px;
}
#input {
    box-sizing: border-box;
    padding: 1em;
    width: 20em;
    max-width: 20em;
    height: 20em;
    max-height: 20em;
}
#output {
    background: rgba(255, 255, 255, 0.97);
    text-align: left;
    animation: bounceInRight 1s;
}
#output pre {
    margin-top: 0;
    padding: 1em;
    border: 4px solid #050A0E;
    overflow: auto;
    max-height: 20em;
    animation: bounceInRight 0.5s;
}
#input, #parse, #parse:active, #parse:focus {
    padding: 1em;
    width: 20em;
    background: #050A0E;
    color: #5EB4E7;
    outline: 0;
    outline-style: none;
    outline-width: 0;
    box-shadow: none;
    border: none;
}
#parse {
    transition: all 225ms ease-in-out;
    border-radius: 0 0 5px 5px;
}
#parse:hover {
    color: rgba(255, 255, 255, 0.8);
    background: #5EB4E7;
    cursor: pointer;
    box-shadow: 0 0 25px #5EB4E7;
}
.containerLabel {
    position: relative;
    top: -0.5em;
    left: -1.5em;
    color: #5EB4E7;
    text-align: left;
    margin-left: 1.5em;
    font-size: 80%;
    font-weight: bold;
    opacity: 0.85;
    margin-bottom: 0.25em;
    text-shadow: 0 0 40px #5EB4E7;
}
.bounceInRight {
    animation: bounceInRight 1s;
}
@keyframes bounceRight {
    0%, 20%, 50%, 80%, 100% {
        transform: translateX(0);
    }
    40% {
        transform: translateX(-10px);
    }
    60% {
        transform: translateX(-5px);
    }
}
@keyframes bounceDown {
    0%, 20%, 50%, 80%, 100% {
        transform: translateY(0);
    }
    40% {
        transform: translateY(-10px);
    }
    60% {
        transform: translateY(-5px);
    }
}
@keyframes bounceInRight {
    0% {
        opacity: 0;
        transform: translateX(2000px);
    }
    60% {
        opacity: 1;
        transform: translateX(-30px);
    }
    80% {
        transform: translateX(10px);
    }
    100% {
        transform: translateX(0);
    }
}
@keyframes flipInY {
    0% {
        transform: perspective(400px) rotateY(90deg);
        opacity: 0;
    }
    40% {
        transform: perspective(400px) rotateY(-10deg);
    }
    70% {
        transform: perspective(400px) rotateY(10deg);
    }
    100% {
        transform: perspective(400px) rotateY(0deg);
        opacity: 1;
    }
}
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1
    }
}
@keyframes scaleIn {
    0% {
        transform: scale(0);
    }
    80% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
    }
}
<link rel="stylesheet" href="style/style.css">
<script src="js/mine-parse.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div id="mainContainer">
  <h1> <i class="fa fa-code"></i> MineParse </h1>
  <div id="inputContainer">
      <div class="containerLabel">
          <i class="fa fa-pencil-square"></i>
          Input
      </div>
      <textarea id="input">
§nMinecraft Formatting

§r§00 §11 §22 §33
§44 §55 §66 §77
§88 §99 §aa §bb
§cc §dd §ee §ff
    
§r§0k §kMinecraft
§rl §lMinecraft
§rm §mMinecraft
§rn §nMinecraft
§ro §oMinecraft
§rr §rMinecraft
      </textarea>
      <button id="parse">
          <i class="fa fa-angle-right"></i>
          Parse
      </button>
  </div>
  <div id="inBetween"></div>
  <div id="outputContainer">
      <div class="containerLabel">
          <i class="fa fa-eye"></i>
          Output <span id="parseTime"></span>
      </div>
      <div id="output"></div>
  </div>
  <script>
      (function () {
          'use strict';
          var input = document.getElementById('input'),
              output = document.getElementById('output'),
              parseBtn = document.getElementById('parse'),
              parseTime = document.getElementById('parseTime'),
              outputContainer = document.getElementById('outputContainer'),
              scrollInterval;
              
          parseBtn.onclick = function () {
              var scrollY = window.pageYOffset,
                  outputY = outputContainer.offsetTop,
                  parseStart = Date.now(),
                  result = mineParse(input.value);
              parseTime.innerHTML = '~ ' + ((Date.now() - parseStart) / 1000) + ' seconds';
              clearInterval(scrollInterval);
              output.innerHTML = '';
              if (window.innerWidth < 850) {
                  scrollInterval = setInterval(function () {
                      scrollY += 5;
                      window.scrollTo(0, scrollY);
                      if (scrollY >= outputY) {
                          window.scrollTo(0, outputY);
                          clearInterval(scrollInterval);
                      }
                  }, 0);
              }
              output.appendChild(result.parsed);
          };
      }());
  </script>

【讨论】:

  • 这个答案很完美!现在我只需要理解这段代码......另外,你将如何将 \n 替换为
    ?还有一个稍微不同的问题。 §k 将文本向前更改,直到它“重置”为随机文本,每 0.1 秒移动一次。现在,你怎么可能在 JavaScript 中做到这一点?
  • 很高兴它对你有用。是的,稍微分析一下并改进一下,它肯定可以使用更多的东西。要替换换行符,您可以使用 /\\n/g 作为正则表达式,以及 replace 函数;像这样的东西:string.replace(/\\n/g, '&lt;br&gt;');。您应该在 for 循环之前替换字符串中的所有换行符(因为否则它会弄乱代码的索引)。嗯,至于那个,它用随机字符替换它找到的每个字符? reset 字符是什么?变化是否可见? (正如它正在发生的那样)。
  • 感谢您的建议。现在,解释随机字符有点困难。它显示在这张图片上。 hydra-media.cursecdn.com/minecraft.gamepedia.com/7/7e/… 。至于重置字符,所有以前的格式都被带走了。
  • 没问题。我想我现在明白了。我已经更新了代码,这次花了​​我一段时间!我认为它现在符合所有规则。检查更新或this。它有点复杂,但“解析”代码的方法几乎相同。随机字符函数称为混淆,它的行为与 Minecraft 中的不完全相同,但可以对其进行修改。如果您需要任何进一步的帮助,请告诉我。祝你好运。
  • 啊哈。您的新代码完全可以理解,此外,它在我的网站上就像一个魅力!感谢您为此付出的所有帮助、时间和精力!我肯定会很好地利用它,并且会记住它是如何、为什么以及是谁提出来的。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 2011-09-05
  • 2018-09-09
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多