@ginstone/nga-api
Version:
206 lines (205 loc) • 7.66 kB
JavaScript
;
// 标签解析
Object.defineProperty(exports, "__esModule", { value: true });
exports.BbsTagParser = void 0;
// 匹配连续[randomblock]的正则
const TagName_1 = require("./TagName");
const PatternFactory_1 = require("./PatternFactory");
const BbsTag_1 = require("./BbsTag");
const RANDOMBLOCK_PATTERN = /(\[randomblock].+?\[\/randomblock])+/g;
// 匹配回复模板的正则
const REPLY_PATTERN = /(\[b]Reply to.+?\[\/b])/g;
// 匹配不规范的td标签
const TD_PATTERN = /\[td(\d+)]/g;
// 匹配不规范的td标签
const TD_PATTERN_2 = /\[td (.+?)]/g;
// 匹配heading的不规范写法
const HEADING_PATTERN = /===(.*?)===/g;
// li标签规范化
const LI_PATTERN_1 = /(<br\/>)*\[\*]/g;
const LI_PATTERN_3 = /\[\/list]/g;
const LI_PATTERN_4 = /\[list]/g;
const LI_PATTERN_5 = /\[li]\[\/li]/g;
class BbsTagParser {
/**
* 解析正文(总入口)
* @param content 正文
*/
static parseContent(content) {
if (!content) {
return new Array();
}
content = this.preHandle(content);
// console.log(content)
return this.parseCode(content);
}
/**
* 解析标签,将一段bbsCode解析为一个标签数组
* @param code 标签
*/
static parseCode(code) {
const res = new Array;
if (!code) {
return res;
}
let i = 0;
// 逐个字符检查是否遇到了可识别的bbsCode
// console.log(code)
while (i < code.length) {
// 如果当前位置不是 [ , 继续搜索
if (code.charAt(i) !== '[') {
i++;
continue;
}
// 裁剪code
const prefixCode = code.substring(0, i);
const suffixCode = code.substring(i);
//当前位置是 [ , 尝试匹配标签名称
const tagName = TagName_1.TagNameUtils.matcher(suffixCode);
if (tagName != null) {
//标签名匹配成功
if (i > 0) {
// 如果i大于0,把前方字符串作为文本加入
res.push(BbsTag_1.BbsTag.text(prefixCode));
}
// 从后段代码中正确的位置截取代码范围
const subCode = this.getSubCode(suffixCode, tagName);
if (subCode) {
// 匹配成功
// 添加本段代码到列表
res.push(new BbsTag_1.BbsTag(tagName, subCode));
// 截断原代码段
code = suffixCode.substring(subCode.length);
i = 0;
}
else {
console.warn("截取失败:", tagName);
console.warn("失败代码:", suffixCode);
i++;
}
}
else {
i++;
}
}
if (i > 0) {
// 循环结束,i依然大于0,表示有剩余文字,添加一个文本节点
res.push(BbsTag_1.BbsTag.text(code));
}
return res;
}
/**
* 对本就会渲染为一行的标签,删除其首尾多余的br换行符
* @param content 正文
* @param tagName 标签名称
*/
static removeBr(content, tagName) {
const pattern = PatternFactory_1.PatternFactory.getPattern("(<br\\/*>)+\\[(\\/*)" + tagName + "]", 'g');
return content.replace(pattern, `[$2${tagName}]`);
}
/**
* 从代码片段中截取指定标签名称的分段
* @param suffixCode 代码片段
* @param tagName 标签名称
*/
static getSubCode(suffixCode, tagName) {
let i = 0;
const start = "[" + tagName;
const end = "[/" + tagName + "]";
while (i < suffixCode.length) {
// 尝试截取的片段
const endIndex = suffixCode.indexOf(end, i) + end.length;
const s = suffixCode.substring(0, endIndex);
// 如果截取范围内标签的起止标记数量相同,认为匹配
if (this.countMatches(s, start) == this.countMatches(s, end)) {
return s;
}
if (endIndex > i) {
i = endIndex;
}
else {
return undefined;
}
}
return undefined;
}
/**
* 统计子字符串在母串中出现的次数
* @param s 母串
* @param search 子串
*/
static countMatches(s, search) {
let count = 0;
let i;
while ((i = s.indexOf(search)) > -1) {
count++;
s = s.substring(i + search.length);
}
return count;
}
/**
* 正文的预处理
* @param content 正文
*/
static preHandle(content) {
// 替换不规范的 ===
{
content = content.replace(HEADING_PATTERN, "[h]$1[/h]");
}
// [*] 标签规范化
{
content = content
// 把所有 [*] 替换为 [/li][li] ,包括前面带/不带换行符的
.replace(LI_PATTERN_1, "[/li][li]")
// 在 [/list] 前添加 [/li]
.replace(LI_PATTERN_3, "[/li][/ul]")
// 在 [list] 后添加 [li]
.replace(LI_PATTERN_4, "[ul][li]")
// 删除多余的空 li
.replace(LI_PATTERN_5, "");
}
// [randomblock] 标签规范化
{
const replacement = new Array;
let matcher;
while (matcher = RANDOMBLOCK_PATTERN.exec(content)) {
replacement.push(matcher[0]);
}
replacement.forEach(r => content = content.replace(r, `[${TagName_1.TagName.randomblocks}]${r}[/${TagName_1.TagName.randomblocks}]`));
}
// 为预设的回复模板添加 quote
{
content = content.replace(REPLY_PATTERN, "[quote]$1[/quote]");
}
//[u][b][i][r][l][h]规范化
{
content = content.replace(/\[(\/*)u]/g, `[$1${TagName_1.TagName.underline}]`);
content = content.replace(/\[(\/*)b]/g, `[$1${TagName_1.TagName.bold}]`);
content = content.replace(/\[(\/*)i]/g, `[$1${TagName_1.TagName.italic}]`);
content = content.replace(/\[(\/*)r]/g, `[$1${TagName_1.TagName.right}]`);
content = content.replace(/\[(\/*)l]/g, `[$1${TagName_1.TagName.left}]`);
content = content.replace(/\[(\/*)h]/g, `[$1${TagName_1.TagName.heading}]`);
}
//删除多余的空格 h list quote
{
content = this.removeBr(content, TagName_1.TagName.heading);
content = this.removeBr(content, TagName_1.TagName.list);
content = this.removeBr(content, TagName_1.TagName.quote);
content = this.removeBr(content, TagName_1.TagName.randomblock);
content = this.removeBr(content, TagName_1.TagName.tr);
content = this.removeBr(content, TagName_1.TagName.td);
content = this.removeBr(content, TagName_1.TagName.table);
}
// td 标签规范化
{
content = content.replace(TD_PATTERN, "[td=width$1]");
content = content.replace(TD_PATTERN_2, "[td=$1]");
}
// @标签规范化
{
content = content.replace(/\[@(.+?)]/g, `[${TagName_1.TagName.at}=$1]$1[/${TagName_1.TagName.at}]`);
}
return content;
}
}
exports.BbsTagParser = BbsTagParser;