修剪线条,与“剪切”一样,但纠正颜色代码

修剪线条,与“剪切”一样,但纠正颜色代码

修剪线条很容易:

print -l $array | cut -$COLUMNS

...但是如果数组的线是彩色的,则剪切是错误的,因为颜色代码计入线的宽度,因此实际上彩色线被剪切得太短。有一些现成的修正吗?粗略地说,如果我一行中有一个彩色单词,我会这样做:

... $(( COLUMNS + 17 ))

……但如果有更多的彩色单词,那当然是错误的。

答案1

您必须以某种方式计算转义码中使用的字符数,然后将它们添加到 $COLUMNS 中。

这是获取计数的方法:

echo -E $mystring | grep -Eoz '\\e\[[0-9;]+m' | sed -e 's/\x00//g' | wc -m
  • echoargs:用于-E保持颜色代码不变,以便我们可以 grep 它们
  • grepargs:用于-E匹配扩展正则表达式,用于-o仅返回行的匹配部分,用于-z替换换行符\x00
  • 然后我们用sed它来剥离\x00字节,最后
  • wc返回字符数

好的,让我们在一些示例字符串上测试一下:

mystring='\e[1;31;3mThis is red text, and \e[1;32mthis is green text \e[0m'
echo -E "$mystring" | grep -Eoz '\\e\[[0-9;]+m' | sed -e 's/\x00//g' | wc -m
echo -e "$mystring"

看起来不错,打印 23,然后应用着色的字符串。现在构建整个东西:

cols=20
mystring='\e[1;31;3mThis is red text, and \e[1;32mthis is green text \e[0m'
# strip the reset escape code from end of the line so it doesn't get counted
mystring=$(echo -E $mystring | sed -e 's/\\e\[0m$//g')
# count the escape codes
countesc=$(echo -E "$mystring" | grep -Eoz '\\e\[[0-9;]+m' | sed -e 's/\x00//g' | wc -m)
# cut the line while accounting for escape codes, and add back the reset escape code to the end
echo -e $(echo -E "$mystring" | cut -b -$((cols+countesc)))"\e[0m"

如果您在最后一个颜色代码之后进行剪切,则此方法有效。必须构建更复杂的东西来考虑颜色代码的位置。

答案2

解决方案可能是使用 gawk(gnu awk,或任何知道如何在拆分时将分隔符保留在数组中的新 awk)来:拆分“转义码”,并计算需要显示的实际字符。

假设:除了转义码之外,您只有“常规可打印字符”。如果您有更复杂的输入,则需要考虑它(修改 $color_escape_codes 值以添加:“|some_other_noncounted_char(s)”)

len=123  # or $COLUMNS, or whatever you want it to be: the nb of chars to cut at
color_escape_codes="$(  printf '\033['  )[0-9;]+m"
gawk -F"${color_escape_codes}" -v len=$len '
    {
        nf=split( $0, a, FS, seps )
        cur=0
        for( i=1; i<=nf; i++ ) {
            cur=cur + length( a[i] )
            if( cur<=len ) {
              printf( "%s%s", a[i], seps[i] )
                if( (cur==len) || (i==nf) ) {
                    print ""
                    break
                }
            } else {
                printf( "%s\n", substr( a[i], 1, (len-(cur-length(a[i]))) ) )
                break
            }
        }
    }'

答案3

这就是我最终的做法。相当简单的东西:

让 'var' 是一个变量,其中包含一些颜色代码:

lenvar=$#var
stripped=$( echo $var | stripcolors )
lenstripped=$#stripped
(( difference = lenvar - lenstripped ))
((correctedwidth = COLUMNS + difference))
echo $var | cut -c -$correctedwidth

...神奇成分:

stripcolors is an alias for sed "s/\x1B\[\([0-9]\{1,2\}\(;[0-9]\{1,2\}\)\?\)\?[mGK]//g"

相关内容