showText.zip
showText.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="./showText.css">
</head>
<body>
<script src="./marked.min.js"></script>
<script src="./showText.js" type="module"></script>
<script type="module">
import ShowText from "./showText.js";
// let input = "【文本-取文本左-->>文本1我是要反转的文本-->>反】"
// let input = "【文本-取文本右-->>【文本-反转文本-->>文本1我是要反转的文本】-->>5】"
// let input = "【文本-取中间-->>文本1我是要反转2的文本-->>1-->>1】"
// let input = "【文本-反转文本-->>【文本-反转文本-->>4324【返回-->>返回】【当前时间】】】我是后缀"
// let input = "【随机数-->>【随机数-->>af2f-->>a5g】-->>【随机数-->>5b-->>7】】"
// let input = "【变量-->>a-->>3>2】【判断-->>【变量-->>a】-->>是-->>否】";
// let input = "【文本-替换-->>我是文本a字符-->>a-->>b】"
// let input = "【权重随机数-->>a,b,c,d-->>4,2,2,1】"
// let input = "【文本-反转文本-->>【当前时间】【文本-注音-->>汉字-->>hanzi】aaa】【当前时间】"
// let input = `a【空格】【变量-->>日期-->>【当前时间-->>年-月-日】】
// 【变量-->>时间-->>【当前时间-->>时:分:秒】】
// 【文本-文字颜色-->>【变量-->>时间】-->>aqua】【换行】
// 【变量-->>日期】`
// let input = "【文本-注音-->>fdsf【文本-反转文本-->>汉字】fdsfsd-->>【文本-反转文本-->>hanzi】】"
// let input = " 【文本-文字颜色-->>【文本-注音-->>fdsf【文本-反转文本-->>汉字】fdsfsd-->>【文本-反转文本-->>hanzi】】-->>aqua】 __完了__"
// let input = `【文本-文字颜色-->>【文本-黑幕-->>黑幕】-->>aqua】`
let input = `【文本-黑幕-->>【文本-文字颜色-->>黑幕-->>aqua】】`
const Show = new ShowText();
// const output = Show.showTextBrowser(input);
const output = Show.showTextWithMarked(input);
document.body.insertAdjacentHTML("beforeend", output);
</script>
</body>
</html>
showText.js
import BrowserReplaceText from "./BrowserReplaceText.js";
const ReplaceText = new BrowserReplaceText();
class ShowText {
errorOutput;
#backText;
constructor() {
this.doTextList = Object.assign({
"文本-反转文本"(text) {
const type = text.match(/-->>([\s\S]*)】/);
return ReplaceText.getReverseText(this.doReplaceToText(type[1]));
},
"文本-取文本左"(text) {
const textState = this.doTextMatchList(text);
return ReplaceText.getTextLeft(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]));
},
"文本-取文本右"(text) {
const textState = this.doTextMatchList(text);
return ReplaceText.getTextRight(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]));
},
"文本-取中间"(text) {
const textState = this.doTextMatchList(text);
return ReplaceText.getTextCenter(this.doReplaceToText(textState[0]), this.doReplaceToText(textState[1]), this.doReplaceToText(textState[2]));
},
"文本-替换"(text) {
const textState = this.doTextMatchList(text);
return this.doReplaceToText(textState[0]).replace(this.doReplaceToText(textState[1]), this.doReplaceToText(textState[2]));
},
"文本-取出数字"(text) {
const textState = this.doTextMatchList(text);
return ReplaceText.getTextNum(this.doReplaceToText(textState[0]));
},
"当前时间"(text) {
const type = text.match(/-->>([\s\S]*)】/);
return ReplaceText.getDate(+new Date(), type && this.doReplaceToText(type[1]));
},
"返回"(text) {
const type = text.match(/-->>([\s\S]*)】/);
this.#backText = this.doReplaceToText(type[1]);
return ''
},
"选择"(text) {
const choiceList = this.doTextMatchList(text);
return this.doReplaceToText(choiceList[ReplaceText.getTextNum(this.doReplaceToText(choiceList[0]))]);
},
"判断"(text) {
const choiceList = this.doTextMatchList(text);
return Function("return " + this.doReplaceToText(choiceList[0]))() ? this.doReplaceToText(choiceList[1]) : this.doReplaceToText(choiceList[2]);
},
"随机数"(text) {
const minMax = this.doTextMatchList(text);
return ReplaceText.getRandom(this.doReplaceToText(minMax[0]), this.doReplaceToText(minMax[1]));
},
"权重随机数"(text) {
const type = this.doTextMatchList(text);
return ReplaceText.getWeightedRandom(this.doReplaceToText(type[0]).split(/[,,]/), this.doReplaceToText(type[1]).split(/[,,]/));
},
"变量"(text) {
const type = this.doTextMatchList(text);
return type.length === 1 ? ReplaceText.getVariable(this.doReplaceToText(type[0])) : ReplaceText.setVariable(this.doReplaceToText(type[0]), this.doReplaceToText(type[1]));
}
}, {
"文本-注音"(text) {
const textState = this.doTextMatchList(text);
return `{{{注音-${this.doReplaceToText(textState[0])}-${this.doReplaceToText(textState[1])}}}}`;
},
"文本-文字颜色"(text) {
const textState = this.doTextMatchList(text);
return `{{{文字颜色-${this.doReplaceToText(textState[0])}-${this.doReplaceToText(textState[1])}}}}`;
},
"文本-黑幕"(text) {
const textState = this.doTextMatchList(text);
return `{{{黑幕-${this.doReplaceToText(textState[0])}}}}`;
},
"换行"() {
return "{{{换行}}}"
},
"空格"() {
return "{{{空格}}}"
},
});
this.doHTMLList = {
"注音"(text) {
const type = this.doHTMLMatchList(text);
return ReplaceText.getRubyHTML(this.doReplaceToHTML(type[0]), type[1]);
},
"文字颜色"(text) {
const type = this.doHTMLMatchList(text);
return ReplaceText.setTextColor(this.doReplaceToHTML(type[0]), type[1]);
},
"黑幕"(text) {
const type = this.doHTMLMatchList(text);
return ReplaceText.getHeimuHTML(this.doReplaceToHTML(type[0]));
},
"换行"() {
return "<br />"
},
"空格"() {
return " "
},
};
}
showTextBrowser(text) {
let resText = text;
if (/【[\s\S]*】/.test(text)) {
text = text.replace(/\s+(?=【)/g, "").replace(/(?<=】)\s+/g, "");
resText = this.doReplaceToText(text);
resText = this.doReplaceToHTML(resText)
}
return this.errorOutput || resText;
}
showTextWithMarked(text) {
return marked.parse(this.showTextBrowser(text));
}
doReplaceToText(text) {
if (/【[\s\S]*】/.test(text)) {
let parts = text.match(/[【】]|[^【】]+/g),
matches = [],
balance = 0, index = 0;
for (let i = 0; i < parts.length; i++) {
if (parts[i] === "【") {
if (balance === 0) {
index = i;
}
balance++;
} else if (parts[i] === "】") {
if (balance === 1) {
matches.push(parts.slice(index, i + 1).join(""));
}
balance--;
if (balance < 0) {
this.errorOutput = 'missing "【"';
return text;
}
}
}
if (balance > 0) {
this.errorOutput = 'missing "】"';
return text;
}
matches?.forEach(matchText => {
text = text.replace(matchText, match => this.doTextMatch(match));
if (this.#backText) {
text = this.#backText;
this.#backText = '';
}
});
}
return text;
}
doReplaceToHTML(text) {
if (/{{{[\s\S]*}}}/.test(text)) {
let parts = text.match(/[\{\}]{3}|[^\{\}]+/g),
matches = [],
balance = 0, index = 0;
for (let i = 0; i < parts.length; i++) {
if (parts[i] === "{{{") {
if (balance === 0) {
index = i;
}
balance++;
} else if (parts[i] === "}}}") {
if (balance === 1) {
matches.push(parts.slice(index, i + 1).join(""));
}
balance--;
}
}
matches?.forEach(matchText => text = text.replace(matchText, match => this.doHTMLMatch(match)) );
}
return text;
}
doTextMatch(match) {
const type = match.match(/【([\s\S]*?)(?:-->>|】)/);
if (type && this.doTextList[type[1]]) {
return this.doTextList[type[1]].call(this, type.input);
} else {
return type.input;
}
}
doHTMLMatch(match) {
const type = match.match(/{{{([\s\S]*?)[-|(?:}}})]/);
if (type && this.doHTMLList[type[1]]) {
return this.doHTMLList[type[1]].call(this, type.input);
} else {
return type.input;
}
}
#getMatchList(type, divide, left, right) {
let list = [], balance = 0, cacheList = [];
type.forEach(item => {
if (item.match(new RegExp(left + "|" + right))) {
balance += (item.match(new RegExp(left, "g")) || []).length;
balance -= (item.match(new RegExp(right, "g")) || []).length;
cacheList.push(item);
if (balance === 0) {
list.push(cacheList.join(divide));
cacheList = [];
}
} else if (balance) {
cacheList.push(item);
} else {
list.push(item);
}
});
return list;
}
doTextMatchList(text) {
const type = text.match(/(?<=-->>)[\s\S]*?(?=-->>|】$)/g);
if (!type) { return [text] }
return this.#getMatchList(type, "-->>", "【", "】");
}
doHTMLMatchList(text) {
const type = text.match(/(?<=-)[\s\S]*?(?=-|(?:}}})$)/g);
if (!type) { return [text] }
return this.#getMatchList(type, "-", "{{{", "}}}");
}
}
export default ShowText;
BrowserReplaceText.js
import ReplaceText from "./ReplaceText.js";
class BrowserReplaceText extends ReplaceText {
constructor() {
super();
}
getReverseText(text) {
let resText = '';
text.split(/({{{[\s\S]*?}}})/).forEach(text => resText += /{{{[\s\S]*}}}/.test(text) ? text : text.split("").reverse().join(""));
return resText;
}
getRubyHTML(text, rt) {
return `<ruby>${text}<rp>(</rp><rt>${rt}</rt><rp>)</rp></ruby>`;
}
setTextColor(text, color) {
if (/^<[\s\S]+>$/.test(text)) {
return text.replace(/^<([\s\S]+?)>/, `<$1 style="color: ${color}">`);
} else {
return `<span style="color: ${color}" >${text}</span>`;
}
}
getHeimuHTML(text) {
if (/^<[\s\S]+>$/.test(text)) {
return text.includes("class=") ?
text.replace(/class="([\s\S]+?)"/, "class='$1 heimu'") :
text.replace(/^<([\s\S]+?)>/, "<$1 class='heimu'>");
} else {
return `<span class="heimu">${text}</span>`;
}
}
}
export default BrowserReplaceText;
ReplaceText.js
class ReplaceText {
#variableMap;
constructor() {
this.#variableMap = {};
}
getReverseText(text) {
let resText = "";
for (let i = text.length - 1; i >= 0; i--) {
resText += text[i];
}
return resText;
}
getTextLeft(text, stamp) {
return text.split(stamp)[0];
}
getTextRight(text, stamp) {
return text.substring(text.indexOf(stamp) + 1);
}
getTextCenter(text, leftStamp, rightStamp) {
let matchType = text.match(new RegExp(`${leftStamp}([\\s\\S]*?)${rightStamp}`));
if (matchType) {
return matchType[1];
} else {
matchType = text.match(new RegExp(`${rightStamp}([\\s\\S]*?)${leftStamp}`));
return matchType ? matchType[1] : text;
}
}
getTextNum(text) {
if (typeof text === "number") {
return text;
}
return text.replace(/\D/g, '');
}
getRandom(min, max) {
return Math.floor(Math.random() * (parseInt(this.getTextNum(max)) - (min = parseInt(this.getTextNum(min))) + 1) + min);
}
getWeightedRandom(randomList, weightedList) {
let sum = 0;
weightedList = weightedList.map(v => parseInt(this.getTextNum(v)));
const r = this.getRandom(1, weightedList.reduce((a,b) => a + b));
for (let i = 0; i < randomList.length; i++) {
sum += weightedList[i];
if (r <= sum) {
return randomList[i];
}
}
}
getDate(newDate = Date.now(), type) {
const date = new Date(newDate),
year = date.getFullYear(),
month = date.getMonth() + 1 + "",
day = date.getDate().toString().padStart(2, '0'),
hour = date.getHours().toString().padStart(2, '0'),
minutes = date.getMinutes().toString().padStart(2, '0'),
seconds = date.getSeconds().toString().padStart(2, '0'),
week = date.getDay(),
weekList = ["星期一", "星期二","星期三", "星期四","星期五", "星期六","星期日"];
if (type) {
if (type === "all") {
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds} ${weekList[week - 1]}`;
}
return type.replace("年", year).replace("月", month).replace("日", day)
.replace("时", hour).replace("分", minutes).replace("秒", seconds)
.replace("星期", weekList[week - 1]);
}
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}`;
}
getVariable(key) {
return this.#variableMap[key];
}
setVariable(key, value) {
this.#variableMap[key] = value;
return ""
}
}
export default ReplaceText;
showText.css
.heimu {
background-color: currentColor;
transition: background-color .2s;
}
.heimu:hover {
background-color: transparent;
}
ruby,
rp,
rt {
background-color: inherit;
}