利用正则实现彩色控制台输出
最近忙了一阵less的二次开发的工作,期间遇到了不少需要向控制台输出彩色文字的需求。翻了下以前同事的代码,发现要么自己拼转义字符串,要么使用一些不太好用的第三方库,总之都不是很合自己的口味。按照自己的口味,一个好的第三方库应该满足如下需求: 要支持丰富的颜色设置,同时设置颜色又不能太累赘,而且要支持console.log的通配符表示方法以减少拼字符串的工作。cli-color和colors的语法类似,都是采用方法来设定字符串颜色: // colors console.log("this is an error".error); // cli-color console.log(clc.red('red') + ' plain ' + clc.blue('blue')); 如果字符串中的颜色比较多,而且字符串中还包含动态数据,那么就需要大量的拼字符串的工作,丑陋且容易出错,因此这种坑爹的方案直接忽略。 既然这些现成的库不好用,干脆就自己写一个。作为一个前端平时自己接触的最多的是html,受html语法的启发,打算采用标签的形式来设置字符颜色,而不是采用方法的形式。比如要输出红绿两种颜色的文本,可以采用如下方式: 那么这种设计是否容易实现呢?在回答这个问题之前我们先简单说一下实现彩色输出的原理。向控制台输出彩色文字主要利用了ansi 中的转义字符(ANSI转义字符表)。众多的转义字符中有一部分是设置控制台的渲染方式的,其中输出控制采用如下语法来声明:
需要特别注意的一点:过这些输出设置不仅对本次输出起效,而且将一直起效,直至遇到新的设置或控制台退出! 所以在使用的时候一定要记得重置颜色设置,免得影响后面的控制台输出。我们通过下面的demo来检验下这些转义字符的功能。注意划红线的语句部分,虽然这条语句中没有对输出进行任何设置,但因为上一条命令中设置了控制台颜色,所以这次输出依然采用的上次的设置。 叙述了这么多,终于可以回答上面的那个问题了:那么这种设计是否容易实现呢?答案是:很简单。我们仅仅需要用这则处理3类字符串就可以了: 转义字符、颜色开始tag,颜色结束tag。处理策略也很简单:
这部分的逻辑已经封并发布到了npm的rich-console模块,下面为具体的实现代码和demo运行结果截图。顺便说一下ANSI中支持的转义内容还很多比如设置背景色、设置加粗、下划线等,但这些支持的并不好,未能动物所下很多都不支持,再加上这些功能更用的比较少,因此这些功能被有意忽略了。 /** * 获得带颜色转义字符的控制台输出模板. * @param {String}tmpl 包含标签的模板字符串 * @param {boolean}isBright 是否高亮,default false * @return {String} * @public */ function getRichTmpl(tmpl,isBright){ if(typeof tmpl == 'object'){ return tmpl; } var fontStyle = isBright = true ? 'u001b[1m' : ''; var ESCAPES = { black : (fontStyle 'u001b[30m'),red : (fontStyle 'u001b[31m'),green : (fontStyle 'u001b[32m'),yellow : (fontStyle 'u001b[33m'),orange : (fontStyle 'u001b[34m'),pink : (fontStyle 'u001b[35m'),cyan : (fontStyle 'u001b[36m'),white : (fontStyle 'u001b[37m'),noColor: 'u001b[0m' } var NO_COLOR = ESCAPES.noColor; var styleStack = []; var reg = new RegExp(( '(\.)' // 由表示的转义字符 '|<(w+)>' // 样式开始标签 '|</(w+)>' // 样式结束标签 ),'g'); var handleTag function(str){ return str.replace(reg,function(m,$1,221); font-weight:700">2,221); font-weight:700">3){ // 若是转义字符之间返回后面的字符 if ($1) { return $1.slice(1); } // 若为不支持的颜色直接忽略,否则返回样式开始字符并将样式压栈 2) { var style = ESCAPES[$2]; if(style){ styleStack.push(style); return style; }else{ return m; } } // 若为不支持的颜色直接忽略,否则从样式栈中弹出当前样式并返回 // 栈顶样式,若栈为空返回系统默认样式 3) { if(ESCAPES[$3]){ styleStack.pop(); var len = styleStack.length; var topStyle = len > 0 ? styleStack[len - 1] : null; return (topStyle ? topStyle : NO_COLOR); }return m; } } // others return m; }) + NO_COLOR; // 最末尾的两个重置用来防止用户标签不闭合进而污染整个控制台输出 }; return handleTag(tmpl); } /** * 向控制台输出彩色文字. * @param {String}cont * @example * showColorText( * '<red>%s <green>%s</green>! </red>',* 'hello',* 'wold' * ); * @public */ output(cont){ // 若用户输入的是一个object则调用系统的console输出object结构 if(typeof cont 'object'){ console.log(cont); return; } var moreArgs = [].slice.call(arguments,1); moreArgs.unshift(getRichTmpl(cont)); console.log.apply(console,moreArgs); } /** * 以红色文字向控制台输出错误信息. * @param {String|Object}cont * @param {Object...} * @public */ outputError(cont){ 'object'){ console.log(cont); }else{ 1); moreArgs.unshift('<red>' + cont '</red>'); output.apply(null,moreArgs); } } module.exports = { getRichTmpl: getRichTmpl,error: outputError,log: output } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |