如何截断string到最大长度而不破坏ANSI转义码

我有一个Node.js中的subprocess,它生成的ANSI-escape彩色输出有时比我的terminal更宽。

我想截断很长的一行,但不要打破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 } }); }); 

接下来的filter本身:

 // 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 } 

你可能想尝试这个微小的NPM库: 可打印的字符

它处理包含零宽度字符和ANSI转义码的string的各种负担。

获取前N个符号而不破坏ANSI代码:

 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' 
Interesting Posts