자르기 선과 동일하지만 색상 코딩이 정확함 [중복]

자르기 선과 동일하지만 색상 코딩이 정확함 [중복]

선을 자르는 것은 쉽습니다:

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색상 코드를 동일하게 유지하여 색상을 파악하는 데 사용됩니다.
  • 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"

관련 정보