1. ホーム
  2. python

[解決済み] Python で文字列から ANSI エスケープシーケンスを削除するにはどうすればよいですか?

2023-01-02 07:24:12

質問

これは私の文字列です。

'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 (except CSI)
        [@-Z\\-_]
    |     # or [ for CSI, followed by a control sequence
        \[
        [0-?]*  # Parameter bytes
        [ -/]*  # Intermediate bytes
        [@-~]   # Final byte
    )
''', re.VERBOSE)
result = ansi_escape.sub('', sometext)

または VERBOSE フラグがない場合は、凝縮された形で

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

デモです。

>>> import re
>>> ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[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 (omitting CSI)
        \x1B
        [@-Z\\-_]
    |   # or a single 8-bit byte Fe (omitting CSI)
        [\x80-\x9A\x9C-\x9F]
    |   # or CSI + control codes
        (?: # 7-bit CSI, ESC [ 
            \x1B\[
        |   # 8-bit CSI, 9B
            \x9B
        )
        [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[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])'
)
result = ansi_escape_8bit.sub(b'', somebytesvalue)

詳しくは

あなたが挙げた例では、4つのCSI (Control Sequence Introducer) コードが含まれており、これは \x1B[ または ESC [ で終わっているため、それぞれSGR(Select Graphic Rendition)コードを含んでいます。 m . パラメータは ( ; セミコロンで区切られた) パラメータは、どのようなグラフィック表示属性を使用するかを端末に伝えます。つまり、それぞれの \x1B[....m の並びに対して、使われる3つのコードは次の通りです。

  • 0(または 00 この例では)。 リセット は、すべての属性を無効にする
  • 1 (または 01 の例では)。 太字
  • 31: (前景)

しかし、ANSI には CSI SGR コード以上のものがあります。CSI だけでも、カーソルを制御したり、行やディスプレイ全体を消去したり、スクロールしたりできます (もちろん、端末がこれをサポートしていればの話ですが)。また、CSI 以外にも、代替フォントを選択するためのコード ( SS2SS3 )、「プライベートメッセージ」(パスワードと同じ)の送信、端末との通信( DCS )、OS ( OSC )、あるいはアプリケーション自体 ( APC は、アプリケーションがカスタム制御コードを通信ストリームにピギーバックする方法です)、さらに文字列を定義するのに役立つコード ( SOS , 文字列の開始。 ST 文字列終端記号)、あるいは、すべてを基本状態に戻す( RIS ). 上記の正規表現はこれらすべてをカバーしています。

しかし、上記の正規表現は ANSI C1 コードのみを削除し、これらのコードがマークアップしている可能性のある追加データ (OSC オープナーと終了 ST コードの間に送信される文字列など) は削除しないことに注意してください。これらを削除するには、この回答の範囲外の追加作業が必要です。