showText.zip

showText.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="./showText.css">
  7. </head>
  8. <body>
  9. <script src="./marked.min.js"></script>
  10. <script src="./showText.js" type="module"></script>
  11. <script type="module">
  12. import ShowText from "./showText.js";
  13. // let input = "【文本-取文本左-->>文本1我是要反转的文本-->>反】"
  14. // let input = "【文本-取文本右-->>【文本-反转文本-->>文本1我是要反转的文本】-->>5】"
  15. // let input = "【文本-取中间-->>文本1我是要反转2的文本-->>1-->>1】"
  16. // let input = "【文本-反转文本-->>【文本-反转文本-->>4324【返回-->>返回】【当前时间】】】我是后缀"
  17. // let input = "【随机数-->>【随机数-->>af2f-->>a5g】-->>【随机数-->>5b-->>7】】"
  18. // let input = "【变量-->>a-->>3>2】【判断-->>【变量-->>a】-->>是-->>否】";
  19. // let input = "【文本-替换-->>我是文本a字符-->>a-->>b】"
  20. // let input = "【权重随机数-->>a,b,c,d-->>4,2,2,1】"
  21. // let input = "【文本-反转文本-->>【当前时间】【文本-注音-->>汉字-->>hanzi】aaa】【当前时间】"
  22. // let input = `a【空格】【变量-->>日期-->>【当前时间-->>年-月-日】】
  23. // 【变量-->>时间-->>【当前时间-->>时:分:秒】】
  24. // 【文本-文字颜色-->>【变量-->>时间】-->>aqua】【换行】
  25. // 【变量-->>日期】`
  26. // let input = "【文本-注音-->>fdsf【文本-反转文本-->>汉字】fdsfsd-->>【文本-反转文本-->>hanzi】】"
  27. // let input = " 【文本-文字颜色-->>【文本-注音-->>fdsf【文本-反转文本-->>汉字】fdsfsd-->>【文本-反转文本-->>hanzi】】-->>aqua】 __完了__"
  28. // let input = `【文本-文字颜色-->>【文本-黑幕-->>黑幕】-->>aqua】`
  29. let input = `【文本-黑幕-->>【文本-文字颜色-->>黑幕-->>aqua】】`
  30. const Show = new ShowText();
  31. // const output = Show.showTextBrowser(input);
  32. const output = Show.showTextWithMarked(input);
  33. document.body.insertAdjacentHTML("beforeend", output);
  34. </script>
  35. </body>
  36. </html>

showText.js

  1. import BrowserReplaceText from "./BrowserReplaceText.js";
  2. const ReplaceText = new BrowserReplaceText();
  3. class ShowText {
  4. errorOutput;
  5. #backText;
  6. constructor() {
  7. this.doTextList = Object.assign({
  8. "文本-反转文本"(text) {
  9. const type = text.match(/-->>([\s\S]*)】/);
  10. return ReplaceText.getReverseText(this.doReplaceToText(type[1]));
  11. },
  12. "文本-取文本左"(text) {
  13. const textState = this.doTextMatchList(text);
  14. return ReplaceText.getTextLeft(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]));
  15. },
  16. "文本-取文本右"(text) {
  17. const textState = this.doTextMatchList(text);
  18. return ReplaceText.getTextRight(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]));
  19. },
  20. "文本-取中间"(text) {
  21. const textState = this.doTextMatchList(text);
  22. return ReplaceText.getTextCenter(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]), this.doReplaceToText(textState[2]));
  23. },
  24. "文本-替换"(text) {
  25. const textState = this.doTextMatchList(text);
  26. return this.doReplaceToText(textState[0]).replace(this.doReplaceToText(textState[1]), this.doReplaceToText(textState[2]));
  27. },
  28. "文本-取出数字"(text) {
  29. const textState = this.doTextMatchList(text);
  30. return ReplaceText.getTextNum(this.doReplaceToText(textState[0]));
  31. },
  32. "当前时间"(text) {
  33. const type = text.match(/-->>([\s\S]*)】/);
  34. return ReplaceText.getDate(+new Date(), type && this.doReplaceToText(type[1]));
  35. },
  36. "返回"(text) {
  37. const type = text.match(/-->>([\s\S]*)】/);
  38. this.#backText = this.doReplaceToText(type[1]);
  39. return ''
  40. },
  41. "选择"(text) {
  42. const choiceList = this.doTextMatchList(text);
  43. return this.doReplaceToText(choiceList[ReplaceText.getTextNum(this.doReplaceToText(choiceList[0]))]);
  44. },
  45. "判断"(text) {
  46. const choiceList = this.doTextMatchList(text);
  47. return Function("return " + this.doReplaceToText(choiceList[0]))() ? this.doReplaceToText(choiceList[1]) : this.doReplaceToText(choiceList[2]);
  48. },
  49. "随机数"(text) {
  50. const minMax = this.doTextMatchList(text);
  51. return ReplaceText.getRandom(this.doReplaceToText(minMax[0]), this.doReplaceToText(minMax[1]));
  52. },
  53. "权重随机数"(text) {
  54. const type = this.doTextMatchList(text);
  55. return ReplaceText.getWeightedRandom(this.doReplaceToText(type[0]).split(/[,,]/), this.doReplaceToText(type[1]).split(/[,,]/));
  56. },
  57. "变量"(text) {
  58. const type = this.doTextMatchList(text);
  59. return type.length === 1 ? ReplaceText.getVariable(this.doReplaceToText(type[0])) : ReplaceText.setVariable(this.doReplaceToText(type[0]), this.doReplaceToText(type[1]));
  60. }
  61. }, {
  62. "文本-注音"(text) {
  63. const textState = this.doTextMatchList(text);
  64. return `{{{注音-${this.doReplaceToText(textState[0])}-${this.doReplaceToText(textState[1])}}}}`;
  65. },
  66. "文本-文字颜色"(text) {
  67. const textState = this.doTextMatchList(text);
  68. return `{{{文字颜色-${this.doReplaceToText(textState[0])}-${this.doReplaceToText(textState[1])}}}}`;
  69. },
  70. "文本-黑幕"(text) {
  71. const textState = this.doTextMatchList(text);
  72. return `{{{黑幕-${this.doReplaceToText(textState[0])}}}}`;
  73. },
  74. "换行"() {
  75. return "{{{换行}}}"
  76. },
  77. "空格"() {
  78. return "{{{空格}}}"
  79. },
  80. });
  81. this.doHTMLList = {
  82. "注音"(text) {
  83. const type = this.doHTMLMatchList(text);
  84. return ReplaceText.getRubyHTML(this.doReplaceToHTML(type[0]), type[1]);
  85. },
  86. "文字颜色"(text) {
  87. const type = this.doHTMLMatchList(text);
  88. return ReplaceText.setTextColor(this.doReplaceToHTML(type[0]), type[1]);
  89. },
  90. "黑幕"(text) {
  91. const type = this.doHTMLMatchList(text);
  92. return ReplaceText.getHeimuHTML(this.doReplaceToHTML(type[0]));
  93. },
  94. "换行"() {
  95. return "<br />"
  96. },
  97. "空格"() {
  98. return "&nbsp;"
  99. },
  100. };
  101. }
  102. showTextBrowser(text) {
  103. let resText = text;
  104. if (/【[\s\S]*】/.test(text)) {
  105. text = text.replace(/\s+(?=【)/g, "").replace(/(?<=】)\s+/g, "");
  106. resText = this.doReplaceToText(text);
  107. resText = this.doReplaceToHTML(resText)
  108. }
  109. return this.errorOutput || resText;
  110. }
  111. showTextWithMarked(text) {
  112. return marked.parse(this.showTextBrowser(text));
  113. }
  114. doReplaceToText(text) {
  115. if (/【[\s\S]*】/.test(text)) {
  116. let parts = text.match(/[【】]|[^【】]+/g),
  117. matches = [],
  118. balance = 0, index = 0;
  119. for (let i = 0; i < parts.length; i++) {
  120. if (parts[i] === "【") {
  121. if (balance === 0) {
  122. index = i;
  123. }
  124. balance++;
  125. } else if (parts[i] === "】") {
  126. if (balance === 1) {
  127. matches.push(parts.slice(index, i + 1).join(""));
  128. }
  129. balance--;
  130. if (balance < 0) {
  131. this.errorOutput = 'missing "【"';
  132. return text;
  133. }
  134. }
  135. }
  136. if (balance > 0) {
  137. this.errorOutput = 'missing "】"';
  138. return text;
  139. }
  140. matches?.forEach(matchText => {
  141. text = text.replace(matchText, match => this.doTextMatch(match));
  142. if (this.#backText) {
  143. text = this.#backText;
  144. this.#backText = '';
  145. }
  146. });
  147. }
  148. return text;
  149. }
  150. doReplaceToHTML(text) {
  151. if (/{{{[\s\S]*}}}/.test(text)) {
  152. let parts = text.match(/[\{\}]{3}|[^\{\}]+/g),
  153. matches = [],
  154. balance = 0, index = 0;
  155. for (let i = 0; i < parts.length; i++) {
  156. if (parts[i] === "{{{") {
  157. if (balance === 0) {
  158. index = i;
  159. }
  160. balance++;
  161. } else if (parts[i] === "}}}") {
  162. if (balance === 1) {
  163. matches.push(parts.slice(index, i + 1).join(""));
  164. }
  165. balance--;
  166. }
  167. }
  168. matches?.forEach(matchText => text = text.replace(matchText, match => this.doHTMLMatch(match)) );
  169. }
  170. return text;
  171. }
  172. doTextMatch(match) {
  173. const type = match.match(/【([\s\S]*?)(?:-->>|】)/);
  174. if (type && this.doTextList[type[1]]) {
  175. return this.doTextList[type[1]].call(this, type.input);
  176. } else {
  177. return type.input;
  178. }
  179. }
  180. doHTMLMatch(match) {
  181. const type = match.match(/{{{([\s\S]*?)[-|(?:}}})]/);
  182. if (type && this.doHTMLList[type[1]]) {
  183. return this.doHTMLList[type[1]].call(this, type.input);
  184. } else {
  185. return type.input;
  186. }
  187. }
  188. #getMatchList(type, divide, left, right) {
  189. let list = [], balance = 0, cacheList = [];
  190. type.forEach(item => {
  191. if (item.match(new RegExp(left + "|" + right))) {
  192. balance += (item.match(new RegExp(left, "g")) || []).length;
  193. balance -= (item.match(new RegExp(right, "g")) || []).length;
  194. cacheList.push(item);
  195. if (balance === 0) {
  196. list.push(cacheList.join(divide));
  197. cacheList = [];
  198. }
  199. } else if (balance) {
  200. cacheList.push(item);
  201. } else {
  202. list.push(item);
  203. }
  204. });
  205. return list;
  206. }
  207. doTextMatchList(text) {
  208. const type = text.match(/(?<=-->>)[\s\S]*?(?=-->>|】$)/g);
  209. if (!type) { return [text] }
  210. return this.#getMatchList(type, "-->>", "【", "】");
  211. }
  212. doHTMLMatchList(text) {
  213. const type = text.match(/(?<=-)[\s\S]*?(?=-|(?:}}})$)/g);
  214. if (!type) { return [text] }
  215. return this.#getMatchList(type, "-", "{{{", "}}}");
  216. }
  217. }
  218. export default ShowText;

BrowserReplaceText.js

  1. import ReplaceText from "./ReplaceText.js";
  2. class BrowserReplaceText extends ReplaceText {
  3. constructor() {
  4. super();
  5. }
  6. getReverseText(text) {
  7. let resText = '';
  8. text.split(/({{{[\s\S]*?}}})/).forEach(text => resText += /{{{[\s\S]*}}}/.test(text) ? text : text.split("").reverse().join(""));
  9. return resText;
  10. }
  11. getRubyHTML(text, rt) {
  12. return `<ruby>${text}<rp>(</rp><rt>${rt}</rt><rp>)</rp></ruby>`;
  13. }
  14. setTextColor(text, color) {
  15. if (/^<[\s\S]+>$/.test(text)) {
  16. return text.replace(/^<([\s\S]+?)>/, `<$1 style="color: ${color}">`);
  17. } else {
  18. return `<span style="color: ${color}" >${text}</span>`;
  19. }
  20. }
  21. getHeimuHTML(text) {
  22. if (/^<[\s\S]+>$/.test(text)) {
  23. return text.includes("class=") ?
  24. text.replace(/class="([\s\S]+?)"/, "class='$1 heimu'") :
  25. text.replace(/^<([\s\S]+?)>/, "<$1 class='heimu'>");
  26. } else {
  27. return `<span class="heimu">${text}</span>`;
  28. }
  29. }
  30. }
  31. export default BrowserReplaceText;

ReplaceText.js

  1. class ReplaceText {
  2. #variableMap;
  3. constructor() {
  4. this.#variableMap = {};
  5. }
  6. getReverseText(text) {
  7. let resText = "";
  8. for (let i = text.length - 1; i >= 0; i--) {
  9. resText += text[i];
  10. }
  11. return resText;
  12. }
  13. getTextLeft(text, stamp) {
  14. return text.split(stamp)[0];
  15. }
  16. getTextRight(text, stamp) {
  17. return text.substring(text.indexOf(stamp) + 1);
  18. }
  19. getTextCenter(text, leftStamp, rightStamp) {
  20. let matchType = text.match(new RegExp(`${leftStamp}([\\s\\S]*?)${rightStamp}`));
  21. if (matchType) {
  22. return matchType[1];
  23. } else {
  24. matchType = text.match(new RegExp(`${rightStamp}([\\s\\S]*?)${leftStamp}`));
  25. return matchType ? matchType[1] : text;
  26. }
  27. }
  28. getTextNum(text) {
  29. if (typeof text === "number") {
  30. return text;
  31. }
  32. return text.replace(/\D/g, '');
  33. }
  34. getRandom(min, max) {
  35. return Math.floor(Math.random() * (parseInt(this.getTextNum(max)) - (min = parseInt(this.getTextNum(min))) + 1) + min);
  36. }
  37. getWeightedRandom(randomList, weightedList) {
  38. let sum = 0;
  39. weightedList = weightedList.map(v => parseInt(this.getTextNum(v)));
  40. const r = this.getRandom(1, weightedList.reduce((a,b) => a + b));
  41. for (let i = 0; i < randomList.length; i++) {
  42. sum += weightedList[i];
  43. if (r <= sum) {
  44. return randomList[i];
  45. }
  46. }
  47. }
  48. getDate(newDate = Date.now(), type) {
  49. const date = new Date(newDate),
  50. year = date.getFullYear(),
  51. month = date.getMonth() + 1 + "",
  52. day = date.getDate().toString().padStart(2, '0'),
  53. hour = date.getHours().toString().padStart(2, '0'),
  54. minutes = date.getMinutes().toString().padStart(2, '0'),
  55. seconds = date.getSeconds().toString().padStart(2, '0'),
  56. week = date.getDay(),
  57. weekList = ["星期一", "星期二","星期三", "星期四","星期五", "星期六","星期日"];
  58. if (type) {
  59. if (type === "all") {
  60. return `${year}-${month}-${day} ${hour}:${minutes}:${seconds} ${weekList[week - 1]}`;
  61. }
  62. return type.replace("年", year).replace("月", month).replace("日", day)
  63. .replace("时", hour).replace("分", minutes).replace("秒", seconds)
  64. .replace("星期", weekList[week - 1]);
  65. }
  66. return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}`;
  67. }
  68. getVariable(key) {
  69. return this.#variableMap[key];
  70. }
  71. setVariable(key, value) {
  72. this.#variableMap[key] = value;
  73. return ""
  74. }
  75. }
  76. export default ReplaceText;

showText.css

  1. .heimu {
  2. background-color: currentColor;
  3. transition: background-color .2s;
  4. }
  5. .heimu:hover {
  6. background-color: transparent;
  7. }
  8. ruby,
  9. rp,
  10. rt {
  11. background-color: inherit;
  12. }