Created
May 15, 2021 14:19
-
-
Save Steve-xmh/e385a04116df59fc49e156b1f1f6dbf5 to your computer and use it in GitHub Desktop.
CQCode Parser and stringifier
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==ClosureCompiler== | |
// @output_file_name default.js | |
// @compilation_level ADVANCED_OPTIMIZATIONS | |
// @language_out ECMASCRIPT_2018 | |
// ==/ClosureCompiler== | |
"use strict"; | |
var cqRegExp = /^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$\,]+?))*)?\]$/; | |
/** | |
* @param {string} cqcode | |
* @returns {*} | |
*/ | |
function parseOne(cqcode) { | |
var matchResult = cqcode.match(cqRegExp); | |
if (matchResult && matchResult.groups) { | |
var data = {}; | |
if (typeof matchResult.groups.params === 'string') { | |
var params = matchResult.groups.params.substring(1).split(','); | |
for (var paramPair of params) { | |
var equalPos = paramPair.indexOf('='); | |
var key = paramPair.substring(0, equalPos); | |
var value = paramPair.substring(equalPos + 1); | |
data[key] = unescapeString(value); | |
} | |
} | |
return { | |
type: matchResult.groups.type, | |
data | |
}; | |
} | |
else { | |
throw new Error('Input isn\'t a single cqcode.'); | |
} | |
} | |
/** | |
* @param {string} cqcode | |
* @returns {*} | |
*/ | |
function parse(cqcode) { | |
var result = []; | |
let str = cqcode; | |
while (str.length) { | |
var nextLeft = str.search(/\[CQ:/); | |
if (nextLeft === -1) { // No more cqcode, push them as text | |
result.push({ | |
type: 'text', | |
data: { text: unescapeString(str) } | |
}); | |
str = ''; | |
} | |
else { | |
if (nextLeft > 0) { | |
result.push({ | |
type: 'text', | |
data: { text: unescapeString(str.substring(0, nextLeft)) } | |
}); | |
} | |
var nextRight = str.search(']'); | |
var cqcode = str.substring(nextLeft, nextRight + 1); | |
result.push(parseOne(cqcode)); | |
str = str.substring(nextRight + 1); | |
} | |
} | |
return result; | |
} | |
/** | |
* @param {string} cqcode | |
* @returns {*} | |
*/ | |
function tryParse(cqcode) { | |
try { | |
return parse(cqcode); | |
} | |
catch { | |
return []; | |
} | |
} | |
var cqEscapes = { | |
'&': '&', | |
',': ',', | |
'[': '[', | |
']': ']' | |
}; | |
/** | |
* @param {string} data | |
* @returns {string} | |
*/ | |
function escapeString(data) { | |
let result = data; | |
for (var key in cqEscapes) { | |
result = result.replaceAll(key, cqEscapes[key]); | |
} | |
return result; | |
} | |
/** | |
* @param {string} data | |
* @returns {string} | |
*/ | |
function unescapeString(data) { | |
let result = data; | |
for (var key in cqEscapes) { | |
result = result.replaceAll(cqEscapes[key], key); | |
} | |
return result; | |
} | |
/** | |
* @param {Array<*>} cqcode | |
* @returns {string} | |
*/ | |
function stringifyOne(cqcode) { | |
return `[CQ:${cqcode.type}${cqcode.data ? `,${Object.entries(cqcode.data).map(v => { | |
if (!['string', 'number'].includes(typeof v[1])) | |
return ''; | |
let a = v[0] + '=' + escapeString(v[1]); | |
return a; | |
}).join(',')}` : ''}]`; | |
} | |
/** | |
* @param {*} cqcode | |
* @returns {string} | |
*/ | |
function stringify(cqcodes) { | |
var result = []; | |
for (var cqcode of cqcodes) { | |
if (cqcode.type === 'text' && cqcode.data?.text) { | |
result.push(cqcode.data.text); | |
} | |
else { | |
result.push(stringifyOne(cqcode)); | |
} | |
} | |
return result.join(''); | |
} | |
module.exports = { | |
'parseOne': parseOne, | |
'parse': parse, | |
'tryParse': tryParse, | |
'escapeString': escapeString, | |
'unescapeString': unescapeString, | |
'stringifyOne': stringifyOne, | |
'stringify': stringify, | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict';var e=/^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$,]+?))*)?\]$/;function f(a){if((a=a.match(e))&&a.groups){var b={};if("string"===typeof a.groups.g){var c=a.groups.g.substring(1).split(","),d;for(d of c)c=d.indexOf("="),b[d.substring(0,c)]=g(d.substring(c+1))}return{type:a.groups.type,data:b}}throw Error("Input isn't a single cqcode.");} | |
function h(a){var b=[];let c=a;for(;c.length;)if(a=c.search(/\[CQ:/),-1===a)b.push({type:"text",data:{text:g(c)}}),c="";else{0<a&&b.push({type:"text",data:{text:g(c.substring(0,a))}});var d=c.search("]");a=c.substring(a,d+1);b.push(f(a));c=c.substring(d+1)}return b}var k={"&":"&",",":",","[":"[","]":"]"};function l(a){for(var b in k)a=a.h(b,k[b]);return a}function g(a){for(var b in k)a=a.h(k[b],b);return a} | |
function m(a){return`[CQ:${a.type}${a.data?`,${Object.entries(a.data).map(b=>["string","number"].includes(typeof b[1])?b[0]+"="+l(b[1]):"").join(",")}`:""}]`}module.exports={parseOne:f,parse:h,tryParse:function(a){try{return h(a)}catch(b){return[]}},escapeString:l,unescapeString:g,stringifyOne:m,stringify:function(a){var b=[],c;for(c of a){let d;"text"===c.type&&(null==(d=c.data)?0:d.text)?b.push(c.data.text):b.push(m(c))}return b.join("")}}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type CQMessage = any | |
const cqRegExp = /^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$\,]+?))*)?\]$/ | |
export function parseOne(cqcode: string): CQMessage { | |
const matchResult = cqcode.match(cqRegExp) | |
if (matchResult && matchResult.groups) { | |
const data: { [_: string]: string } = {} | |
if (typeof matchResult.groups.params === 'string') { | |
const params = matchResult.groups.params.substring(1).split(',') | |
for (const paramPair of params) { | |
const equalPos = paramPair.indexOf('=') | |
const key = paramPair.substring(0, equalPos) | |
const value = paramPair.substring(equalPos + 1) | |
data[key] = unescapeString(value) | |
} | |
} | |
return { | |
type: matchResult.groups.type, | |
data | |
} | |
} else { | |
throw new Error('Input isn\'t a single cqcode.') | |
} | |
} | |
export function parse(cqcode: string): CQMessage[] { | |
const result = [] | |
let str = cqcode | |
while (str.length) { | |
const nextLeft = str.search(/\[CQ:/) | |
if (nextLeft === -1) { // No more cqcode, push them as text | |
result.push({ | |
type: 'text', | |
data: { text: unescapeString(str) } | |
}) | |
str = '' | |
} else { | |
if (nextLeft > 0) { | |
result.push({ | |
type: 'text', | |
data: { text: unescapeString(str.substring(0, nextLeft)) } | |
}) | |
} | |
const nextRight = str.search(']') | |
const cqcode = str.substring(nextLeft, nextRight + 1) | |
result.push(parseOne(cqcode)) | |
str = str.substring(nextRight + 1) | |
} | |
} | |
return result | |
} | |
export function tryParse(cqcode: string): CQMessage[] { | |
try { | |
return parse(cqcode) | |
} catch { | |
return [] | |
} | |
} | |
const cqEscapes: { [char: string]: string } = { | |
'&': '&', | |
',': ',', | |
'[': '[', | |
']': ']' | |
} | |
export function escapeString(data: string) { | |
let result = data | |
for (const key in cqEscapes) { | |
result = result.replaceAll(key, cqEscapes[key]) | |
} | |
return result | |
} | |
export function unescapeString(data: string) { | |
let result = data | |
for (const key in cqEscapes) { | |
result = result.replaceAll(cqEscapes[key], key) | |
} | |
return result | |
} | |
export function stringifyOne(cqcode: CQMessage) { | |
return `[CQ:${cqcode.type}${cqcode.data ? `,${Object.entries(cqcode.data).map(v => { | |
if (!['string', 'number'].includes(typeof v[1])) return '' | |
let a = v[0] + '=' + escapeString(v[1] as string) | |
return a | |
}).join(',') | |
}` : ''}]` | |
} | |
export function stringify(cqcodes: CQMessage[]) { | |
const result = [] | |
for (const cqcode of cqcodes) { | |
if (cqcode.type === 'text' && cqcode.data?.text) { | |
result.push(cqcode.data.text) | |
} else { | |
result.push(stringifyOne(cqcode)) | |
} | |
} | |
return result.join('') | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment