UFO ET IT

파이썬의 문자열에서 ANSI 이스케이프 시퀀스를 제거하는 방법

ufoet 2021. 1. 9. 10:36
반응형

파이썬의 문자열에서 ANSI 이스케이프 시퀀스를 제거하는 방법


이것은 내 문자열입니다.

'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'

SSH 명령에서 출력을 검색하는 코드를 사용하고 있었고 내 문자열에 'examplefile.zip'만 포함하고 싶습니다.

추가 이스케이프 시퀀스를 제거하기 위해 무엇을 사용할 수 있습니까?


정규 표현식으로 삭제하십시오.

import re

# 7-bit C1 ANSI sequences
ansi_escape = re.compile(r'''
    \x1B    # ESC
    [@-_]   # 7-bit C1 Fe
    [0-?]*  # Parameter bytes
    [ -/]*  # Intermediate bytes
    [@-~]   # Final byte
''', re.VERBOSE)
result = ansi_escape.sub('', sometext)

또는 VERBOSE플래그 없이 압축 된 형식으로 :

ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
result = ansi_escape.sub('', sometext)

데모:

>>> import re
>>> ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
>>> sometext = 'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'
>>> ansi_escape.sub('', sometext)
'ls\r\nexamplefile.zip\r\n'

위의 정규식은 모든 7 비트 ANSI C1 이스케이프 시퀀스를 다루지 만 8 비트 C1 이스케이프 시퀀스 오프너는 다루지 않습니다 . 후자는 동일한 범위의 바이트가 다른 의미를 갖는 오늘날의 UTF-8 세계에서 사용되지 않습니다.

8 비트 코드도 다룰 필요가 있고 bytes값으로 작업하는 경우 정규식은 다음과 같은 바이트 패턴이됩니다.

# 7-bit and 8-bit C1 ANSI sequences
ansi_escape_8bit = re.compile(br'''
    (?: # either 7-bit C1, two bytes, ESC Fe
        \x1B
        [@-_]
    |   # or a single 8-bit byte Fe
        [\x80-\x9F]
    )
    [0-?]*  # Parameter bytes
    [ -/]*  # Intermediate bytes
    [@-~]   # Final byte
''', re.VERBOSE)
result = ansi_escape_8bit.sub(b'', somebytesvalue)

압축 될 수있는

# 7-bit and 8-bit C1 ANSI sequences
ansi_escape_8bit = re.compile(br'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
result = ansi_escape_8bit.sub(b'', somebytesvalue)

자세한 내용은 다음을 참조하십시오.

제공 한 예제에는 \x1B[또는 ESC[ 여는 바이트 로 표시되는 4 개의 CSI (Control Sequence Introducer) 코드 가 포함되어 있으며 각 코드에는 SGR (Select Graphic Rendition) 코드가 포함되어 있습니다 m. 이들 ;사이 의 매개 변수 ( 세미콜론 으로 구분)는 사용할 그래픽 변환 속성을 터미널에 알려줍니다. 따라서 각 \x1B[....m시퀀스 에 대해 사용되는 3 개의 코드는 다음과 같습니다.

  • 0 (또는 00이 예에서) : reset , 모든 속성 비활성화
  • 1 (또는 01예에서) : 굵게
  • 31 : 빨간색 (전경)

그러나 ANSI에는 CSI SGR 코드보다 더 많은 것이 있습니다. CSI만으로도 커서를 제어하고, 라인을 지우거나 전체 디스플레이를 제어하거나 스크롤 할 수 있습니다 (물론 터미널이이를 지원하는 경우). 그리고 CSI 외에도 대체 글꼴 ( SS2SS3) 을 선택 하고 , '비공개 메시지'(비밀번호 생각)를 전송하고, 터미널 ( DCS), OS ( OSC) 또는 애플리케이션 자체 () APC와 통신하는 코드가 있습니다. 사용자 정의 제어 코드를 통신 스트림에 피기 백)하고 문자열을 정의하는 데 도움이되는 추가 코드 ( SOS, 문자열의 시작, ST문자열 종결 자) 또는 모든 것을 기본 상태로 다시 재설정 ( RIS)합니다. 위의 정규식은이 모든 것을 다룹니다.


이 질문에 대한 대답은 색상과 글꼴 효과 만 고려합니다. 커서 위치 지정, 지우기 및 스크롤 영역과 같이 'm'으로 끝나지 않는 시퀀스가 ​​많이 있습니다.

제어 시퀀스 (ANSI 이스케이프 시퀀스라고도 함)에 대한 완전한 정규식은 다음과 같습니다.

/(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/

를 참조하십시오 ECMA-48 5.4 절ANSI 이스케이프 코드


함수

Jeff의 regexp 에 대한 Martijn Pieters ♦의 답변기반으로 합니다.

def escape_ansi(line):
    ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
    return ansi_escape.sub('', line)

테스트

def test_remove_ansi_escape_sequence(self):
    line = '\t\u001b[0;35mBlabla\u001b[0m                                  \u001b[0;36m172.18.0.2\u001b[0m'

    escaped_line = escape_ansi(line)

    self.assertEqual(escaped_line, '\tBlabla                                  172.18.0.2')

테스팅

혼자서 실행하려면 python3(더 나은 유니 코드 지원, blablabla)를 사용하십시오. 테스트 파일은 다음과 같습니다.

import unittest
import re

def escape_ansi(line):

class TestStringMethods(unittest.TestCase):
    def test_remove_ansi_escape_sequence(self):

if __name__ == '__main__':
    unittest.main()

제안 된 정규식은 나를 위해 트릭을 수행하지 않았으므로 내 자신의 것을 만들었습니다. 다음은 여기 에서 찾은 사양을 기반으로 만든 파이썬 정규식입니다.

ansi_regex = r'\x1b(' \
             r'(\[\??\d+[hl])|' \
             r'([=<>a-kzNM78])|' \
             r'([\(\)][a-b0-2])|' \
             r'(\[\d{0,2}[ma-dgkjqi])|' \
             r'(\[\d+;\d+[hfy]?)|' \
             r'(\[;?[hf])|' \
             r'(#[3-68])|' \
             r'([01356]n)|' \
             r'(O[mlnp-z]?)|' \
             r'(/Z)|' \
             r'(\d+)|' \
             r'(\[\?\d;\d0c)|' \
             r'(\d;\dR))'
ansi_escape = re.compile(ansi_regex, flags=re.IGNORECASE)

다음 스 니펫에서 정규식을 테스트했습니다 (기본적으로 ascii-table.com 페이지의 복사 붙여 넣기).

\x1b[20h    Set
\x1b[?1h    Set
\x1b[?3h    Set
\x1b[?4h    Set
\x1b[?5h    Set
\x1b[?6h    Set
\x1b[?7h    Set
\x1b[?8h    Set
\x1b[?9h    Set
\x1b[20l    Set
\x1b[?1l    Set
\x1b[?2l    Set
\x1b[?3l    Set
\x1b[?4l    Set
\x1b[?5l    Set
\x1b[?6l    Set
\x1b[?7l    Reset
\x1b[?8l    Reset
\x1b[?9l    Reset
\x1b=   Set
\x1b>   Set
\x1b(A  Set
\x1b)A  Set
\x1b(B  Set
\x1b)B  Set
\x1b(0  Set
\x1b)0  Set
\x1b(1  Set
\x1b)1  Set
\x1b(2  Set
\x1b)2  Set
\x1bN   Set
\x1bO   Set
\x1b[m  Turn
\x1b[0m Turn
\x1b[1m Turn
\x1b[2m Turn
\x1b[4m Turn
\x1b[5m Turn
\x1b[7m Turn
\x1b[8m Turn
\x1b[1;2    Set
\x1b[1A Move
\x1b[2B Move
\x1b[3C Move
\x1b[4D Move
\x1b[H  Move
\x1b[;H Move
\x1b[4;3H   Move
\x1b[f  Move
\x1b[;f Move
\x1b[1;2    Move
\x1bD   Move/scroll
\x1bM   Move/scroll
\x1bE   Move
\x1b7   Save
\x1b8   Restore
\x1bH   Set
\x1b[g  Clear
\x1b[0g Clear
\x1b[3g Clear
\x1b#3  Double-height
\x1b#4  Double-height
\x1b#5  Single
\x1b#6  Double
\x1b[K  Clear
\x1b[0K Clear
\x1b[1K Clear
\x1b[2K Clear
\x1b[J  Clear
\x1b[0J Clear
\x1b[1J Clear
\x1b[2J Clear
\x1b5n  Device
\x1b0n  Response:
\x1b3n  Response:
\x1b6n  Get
\x1b[c  Identify
\x1b[0c Identify
\x1b[?1;20c Response:
\x1bc   Reset
\x1b#8  Screen
\x1b[2;1y   Confidence
\x1b[2;2y   Confidence
\x1b[2;9y   Repeat
\x1b[2;10y  Repeat
\x1b[0q Turn
\x1b[1q Turn
\x1b[2q Turn
\x1b[3q Turn
\x1b[4q Turn
\x1b<   Enter/exit
\x1b=   Enter
\x1b>   Exit
\x1bF   Use
\x1bG   Use
\x1bA   Move
\x1bB   Move
\x1bC   Move
\x1bD   Move
\x1bH   Move
\x1b12  Move
\x1bI  
\x1bK  
\x1bJ  
\x1bZ  
\x1b/Z 
\x1bOP 
\x1bOQ 
\x1bOR 
\x1bOS 
\x1bA  
\x1bB  
\x1bC  
\x1bD  
\x1bOp 
\x1bOq 
\x1bOr 
\x1bOs 
\x1bOt 
\x1bOu 
\x1bOv 
\x1bOw 
\x1bOx 
\x1bOy 
\x1bOm 
\x1bOl 
\x1bOn 
\x1bOM 
\x1b[i 
\x1b[1i
\x1b[4i
\x1b[5i

바라건대 이것은 다른 사람들에게 도움이 될 것입니다 :)


미래의 Stack Overflowers에 도움이된다면 크레용 라이브러리사용 하여 Python 출력에 시각적 효과를 조금 더 부여했습니다. Windows와 Linux 플랫폼 모두에서 작동하므로 유리합니다. 그러나 나는 화면에 표시하고 로그 파일에 추가했으며 이스케이프 시퀀스는 로그 파일의 가독성에 영향을 미치므로 제거하고 싶었습니다. 그러나 크레용으로 삽입 된 이스케이프 시퀀스는 오류를 생성했습니다.

expected string or bytes-like object

해결책은 매개 변수를 문자열로 캐스트하는 것이기 때문에 일반적으로 받아 들여지는 대답에 약간의 수정 만 필요했습니다.

def escape_ansi(line):
    ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
    return ansi_escape.sub('', str(line))

if you want to remove the \r\n bit, you can pass the string through this function (written by sarnold):

def stripEscape(string):
    """ Removes all escape sequences from the input string """
    delete = ""
    i=1
    while (i<0x20):
        delete += chr(i)
        i += 1
    t = string.translate(None, delete)
    return t

Careful though, this will lump together the text in front and behind the escape sequences. So, using Martijn's filtered string 'ls\r\nexamplefile.zip\r\n', you will get lsexamplefile.zip. Note the ls in front of the desired filename.

I would use the stripEscape function first to remove the escape sequences, then pass the output to Martijn's regular expression, which would avoid concatenating the unwanted bit.

ReferenceURL : https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python

반응형