Javascript 如何在不破坏ANSI转义码的情况下将字符串截断到最大长度

Javascript 如何在不破坏ANSI转义码的情况下将字符串截断到最大长度,javascript,node.js,ansi-escape,Javascript,Node.js,Ansi Escape,我在Node.js中有一个子进程,它生成的输出有时比我的终端宽 我想截断长行,但不破坏ANSI颜色代码,也不计算不可见字符(这样带有大量转义符的行就不会太短)首先,您需要确保处理来自stdout的完整行,这可能会在行之间产生片段: var acc = ''; child.stdout.setEncoding('utf8'); // get strings rather than buffers child.stdout.on('data', function(data){ // wh

我在Node.js中有一个子进程,它生成的输出有时比我的终端宽


我想截断长行,但不破坏ANSI颜色代码,也不计算不可见字符(这样带有大量转义符的行就不会太短)

首先,您需要确保处理来自
stdout
的完整行,这可能会在行之间产生片段:

var acc = '';
child.stdout.setEncoding('utf8');       // get strings rather than buffers
child.stdout.on('data', function(data){ // when output is written by child

    // split lines, including linebreaks:
    data.split(/(\r?\n)/).forEach(function(frag) {
        if (frag == '\r\n' || frag == '\n') {        // if linebreak,
            console.log(filterAnsi(acc, width));     //   output filtered completed line
            acc = '';                                //   clear accumulator line
        } else {                                     // if not linebreak,
            acc += frag;                             //   add fragment to accumulator
        }
    });
});
接下来是过滤器本身:

// Crop the length of lines, ANSI escape code aware
// Always outputs every escape char, regardless of length (so we always end up with a sane state)
// Visible characters are filtered out once length is exceeded
function filterAnsi(str, len) {
    if (!len || len < 10) return str; // probably not a valid console -- send back the whole line
    var count = 0,        // number of visible chars on line so far
        esc = false,      // in an escape sequence
        longesc = false;  // in a multi-character escape sequence
    var outp = true;      // should output this character
    return str.split('').filter(function(c){ // filter characters...
        if (esc && !longesc && c == '[') longesc = true; // have seen an escape, now '[', start multi-char escape
        if (c == '\x1b') esc = true; // start of escape sequence

        outp = (count < len || esc); // if length exceeded, don't output non-escape chars
        if (!esc && !longesc) count++; // if not in escape, count visible char

        if (esc && !longesc && c != '\x1b') esc = false; // out of single char escape
        if (longesc && c != '[' && c >= '@' && c <= '~') {esc=false; longesc=false;} // end of multi-char escape

        return outp; // result for filter
    }).join(''); // glue chars back into string
}
//裁剪行的长度,ANSI转义码感知
//总是输出每个转义字符,不管长度如何(因此我们总是以一个正常状态结束)
//一旦超过长度,可见字符将被过滤掉
函数过滤器ASI(str,len){
如果(!len | | len<10)返回str;//可能不是一个有效的控制台——返回整行
var count=0,//到目前为止,行上的可见字符数
esc=false,//在转义序列中
longesc=false;//在多字符转义序列中
var outp=true;//应输出此字符
返回str.split(“”).filter(函数(c){//筛选字符。。。
如果(esc&&!longesc&&c='[')longesc=true;//已看到转义,现在为'[',启动多字符转义
如果(c=='\x1b')esc=true;//转义序列的开始
outp=(count如果(longesc&&c!='['&&c>='@'&&c您可能想要尝试这个小小的NPM库:(注意:我是这个库的作者)

它通过处理包含零宽度字符和ANSI转义码的字符串来处理各种负担

在不破坏ANSI代码的情况下获取前N个符号:

const { first } = require ('printable-characters')

const s = '\u001b[22mfoobar\u001b[22m'

first (s, 0) // === '\u001b[22m\u001b[22m'
first (s, 1) // === '\u001b[22mf\u001b[22m'
first (s, 3) // === '\u001b[22mfoo\u001b[22m'
first (s, 6) // === '\u001b[22mfoobar\u001b[22m'