利用正则实现彩色控制台输出

最近忙了一阵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语法的启发,打算采用标签的形式来设置字符颜色,而不是采用方法的形式。比如要输出红绿两种颜色的文本,可以采用如下方式: Foo.log('<red>red color <green>green color</green></red>')。这种方式有两个优点: 第一,便于表现丰富的颜色,尤其是颜色嵌套的情况,如果采用cli-color那种方式来表现多个颜色的嵌套,估计拼字符串会让你想吐;第二,省去了记忆方法名和拼字符串。

那么这种设计是否容易实现呢? 在回答这个问题之前我们先简单说一下实现彩色输出的原理。向控制台输出彩色文字主要利用了ansi 中的转义字符(ANSI转义字符表)。众多的转义字符中有一部分是设置控制台的渲染方式的,其中输出控制采用如下语法来声明:\x1b[nm。x1b的值是27,在ASC码表中表示转义字符,后面的[nm是模式设置,[和m是常量,n为变量。通过设置N的值可以实现不同的输出设置,下面为常用的N值

  • 0 开始以暗色模式显示文本, 文字颜色为用户设置的控制台默认颜色,一般为白色
  • 1 开始以亮色模式显示文本, 文字颜色为用户设置的控制台默认颜色,一般为白色
  • 30 ~ 27 分别以black、red、green、 yellow、blue、pink、cyan、white颜色来显示文本

需要特别注意的一点:过这些输出设置不仅对本次输出起效,而且将一直起效,直至遇到新的设置或控制台退出! 所以在使用的时候一定要记得重置颜色设置,免得影响后面的控制台输出。我们通过下面的demo来检验下这些转义字符的功能。注意划红线的语句部分,虽然这条语句中没有对输出进行任何设置,但因为上一条命令中设置了控制台颜色,所以这次输出依然采用的上次的设置。

叙述了这么多,终于可以回答上面的那个问题了:那么这种设计是否容易实现呢?答案是: 很简单。我们仅仅需要用这则处理3类字符串就可以了: 转义字符、颜色开始tag,颜色结束tag。处理策略也很简单:

  • 遇到由斜线开始的转义字符, 直接返回斜线后面的字符
  • 遇到开始Tag, 查看是否为支持的颜色,若不支持,不做处理原样返回;若支持,返回tag对应到 颜色转义字符,并将该颜色转义字符压栈。
  • 遇到结束Tag, 查看是否是支持的颜色,若不支持,不做处理原样返回;若支持,弹栈并返回栈顶颜色对应的转义字符,若栈为空,则设置为系统默认颜色。
  • 其他情况一律不做处理,原样返回(这一步主要是预防自己没有预料的一些匹配出现,这个例子中应该用不到,为了保险起见还是留着吧)。
  • 为了防止用户标签没有闭合而影响其他控制台输出,在最后预防行的设置颜色为默认颜色。

这部分的逻辑已经封并发布到了npm的rich-console模块,下面为具体的实现代码和demo运行结果截图。顺便说一下ANSI中支持的转义内容还很多比如设置背景色、设置加粗、下划线等,但这些支持的并不好,Windows下很多都不支持,再加上这些功能更用的比较少,因此这些功能被有意忽略了。

/**
 * 获得带颜色转义字符的控制台输出模板.
 * @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[33m'),
        blue   : (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, $2, $3){
            // 若是转义字符之间返回\后面的字符
            if ($1) { return $1.slice(1); }

            // 若为不支持的颜色直接忽略,否则返回样式开始字符并将样式压栈
            if ($2) {
                var style = ESCAPES[$2];
                if(style){
                    styleStack.push(style);
                    return style;
                }else{
                    return m;
                }
            }              

            // 若为不支持的颜色直接忽略,否则从样式栈中弹出当前样式并返回
            // 栈顶样式,若栈为空返回系统默认样式
            if ($3) {
                if(ESCAPES[$3]){
                    styleStack.pop();
                    var len = styleStack.length;
                    var topStyle = len > 0 ? styleStack[len - 1] : null;
                    return (topStyle ? topStyle : NO_COLOR);
                }else{
                    return m;
                }
            }

            // others
            return m;
        }) + NO_COLOR; // 最末尾的两个重置用来防止用户标签不闭合进而污染整个控制台输出
    };

    return handleTag(tmpl);
}

/**
 * 向控制台输出彩色文字.
 * @param {String}cont
 * @example
 *   showColorText(
 *      '<red>%s <green>%s</green>! </red>',
 *      'hello',
 *      'wold'
 *   );
 * @public
 */
function 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
 */
function outputError(cont){
    if(typeof cont == 'object'){
        console.log(cont);
    }else{
        var moreArgs = [].slice.call(arguments, 1);
        moreArgs.unshift('<red>' + cont + '</red>');
        output.apply(null, moreArgs);
    }
}

module.exports = {
    getRichTmpl: getRichTmpl,
    error: outputError,
    log: output
}
时间: 2024-08-01 09:13:45

利用正则实现彩色控制台输出的相关文章

python通过colorama模块在控制台输出彩色文字的方法_python

本文实例讲述了python通过colorama模块在控制台输出彩色文字的方法.分享给大家供大家参考.具体分析如下: colorama是一个python专门用来在控制台.命令行输出彩色文字的模块,可以跨平台使用,在windows下linux下都工作良好,如果你想让控制台的输出信息更漂亮一些,可以使用给这个模块. colorama官方地址:https://pypi.python.org/pypi/colorama 安装colorama模块 pip install colorama 使用范例 from

Windows下的控制台输出

控制台输出就象dos下的输出,可不是图形界面.象ping/ipconfig/ftp等命令都是这类程序. 回忆过去,在dos下进行文件操作时,常用到"文件把柄"的概念,使用文件把柄操作时,非常方便,操作时,只要知道把柄号就可以,而不用操心文件的位置.dos下,设备也都有自己的专用把柄,这些把柄是:0000H 标准输入设备 (stdin)0001H 标准输出设备 (stdout)0002H 标准错误设备 (stderr)0003H 标准辅助设备 (stdaux)0004H 标准打印设备 (

console-求windows api 让其他进程向当前控制台输出

问题描述 求windows api 让其他进程向当前控制台输出 求一个 windows api 能解决下面问题 创建了一个进程,设定为新开控制台,并隐藏.(功能就是没隔一秒输出一个数字) 在之后的程序执行中,需要将这个进程的输出打在当前控制台上. si.wShowWindow = SW_HIDE; si.wShowWindow = SW_HIDE; CreateProcess(NULL, appName, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,

在Wordpress iNove主题中利用Simple Tags插件实现输出相关日志的方法

考虑各方面的情况,我没有采用其他一些wordpress相关日志(RelatedPosts)插件,而是充分应用Simple Tags插件强大的相关日志,相关标签功能,结合iNove主题,利用Simple Tags实现了输出相关日志的功能,感觉还不错.虽然Simple Tags可以通过后台设定相关日志,但是添加的相关日志列表不能控制其出现的位置. 安装步骤如下: 第一步:下载并安装Simple Tags插件.为什么要先安装这个插件呢?因为Simple Tags插件可以根据标签产生相关日志. 第二步:

tomcat控制台输出信息时会卡住的原因

在window2003 系统下运行tomcat5.5 当运行时代码中有控制台输出的语句,如System.out.println 或 e.printStackTrace() 时,当前线程会卡住,而且控制台没有任何输出,只要在运行的服务器上敲下空格或回车,才回有输出,该线程才恢复运行. 原因: 1 在控制台左上角鼠标右键,选属性 2 看图上的解释,去掉那个快速编辑 3 这个你根据情况自己决定吧.我一般选下面那个

python在控制台输出进度条的方法

  本文实例讲述了python在控制台输出进度条的方法.分享给大家供大家参考.具体实现方法如下: 进度条效果如下所示: ? 1 2 |#############################---------------------| 59 percent done 代码如下: ? 1 2 3 4 5 6 7 8 9 class ProgressBar(): def __init__(self, width=50): self.pointer = 0 self.width = width de

PowerShell在控制台输出特殊符号的方法

  这篇文章主要介绍了PowerShell在控制台输出特殊符号的方法,本文给出了实现代码和输出图例,本文代码输出了一个绿色三角形,需要的朋友可以参考下 您知道吗,PowerShell控制台也可以输出特殊的图标?而你需要做的只是,设置控制台的字体为TrueType 字体,比如"Consolas". 要显示特殊字符,请使用十进制或十六进制字符代码,例如: ? 1 2 [Char]8730 [Char]0x25BA 或着打开系统上内置的应用程序 "CharacterMap"

junit测试报错,求大神救命,控制台输出如下,

问题描述 junit测试报错,求大神救命,控制台输出如下, 0 2015-07-09 09:04:52182 [main] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - #org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:316)# -

cmd-C#隐式运行CMD命令,并获取控制台输出

问题描述 C#隐式运行CMD命令,并获取控制台输出 正在用C#做一个简易的使用mingw的IDE程序,使用cmd.exe中通过gcc命令进行编译链接等操作,想要及时获取 错误以及警告信息 进行输出. 开始时参照 C#程序调用cmd.exe执行命令 代码如下: using System.Diagnostics; public class CmdHelper { private static string CmdPath = @"C:WindowsSystem32cmd.exe"; ///