これは私の文字列です:
'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'
コードを使用してSSHコマンドから出力を取得していましたが、文字列に「examplefile.zip」のみを含める必要があります
余分なエスケープシーケンスを削除するために何を使用できますか?
これは私の文字列です:
'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)
詳細については、以下を参照してください。
\x1B[
与えた例には、またはESC[
オープニングバイトでマークされた4つのCSI(Control Sequence Introducer)コードが含まれており、それぞれがで終わるため、SGR(Select Graphic Rendition)コードが含まれていますm
。それらの間にあるパラメーター(セミコロンで区切られて;
いる)は、使用するグラフィックレンディション属性を端末に指示します。したがって、各\x1B[....m
シーケンスで使用される3つのコードは次のとおりです。
00
この例では):リセット、すべての属性を無効にする01
例では):太字ただし、ANSIには、CSISGRコードだけではありません。CSIだけを使用すると、カーソルを制御したり、行や表示全体をクリアしたり、スクロールしたりすることもできます(もちろん、端末がこれをサポートしている場合)。また、CSI以外にも、代替フォント(SS2
およびSS3
)を選択したり、「プライベートメッセージ」(パスワードを考えたり)を送信したり、端末(DCS
)、OS(OSC
)、またはアプリケーション自体(APC
、アプリケーションがカスタム制御コードを通信ストリームにピギーバックします)、さらに文字列の定義に役立つコード(SOS
、文字列の開始、文字ST
列ターミネータ)、またはすべてを基本状態にリセットするためのコード(RIS
)。上記の正規表現は、これらすべてをカバーしています。
ただし、上記の正規表現はANSI C1コードのみを削除し、それらのコードがマークアップする可能性のある追加データ(OSCオープナーと終了STコードの間で送信される文字列など)は削除しないことに注意してください。それらを削除するには、この回答の範囲外で追加の作業が必要になります。
この質問に対する受け入れられた答えは、色とフォントの効果のみを考慮しています。カーソルの配置、消去、スクロール領域など、「m」で終わらないシーケンスがたくさんあります。
制御シーケンス(別名ANSIエスケープシーケンス)の完全な正規表現は次のとおりです。
/(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/
ECMA-48セクション5.4およびANSIエスケープコードを参照してください
MartijnPieters♦のJeffの正規表現による回答に基づいています。
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()
提案された正規表現は私のためにトリックをしなかったので、私は自分のものを作成しました。以下は、ここにある仕様に基づいて作成したPython正規表現です。
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
うまくいけば、これは他の人を助けるでしょう:)
将来のStackOverflowersに役立つ場合は、クレヨンライブラリを使用して、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))
ビットを削除したい場合は\r\n
、この関数(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
ただし、これにより、エスケープシーケンスの前後のテキストがひとまとめになります。したがって、Martijnのフィルタリングされた文字列を使用'ls\r\nexamplefile.zip\r\n'
すると、が取得されますlsexamplefile.zip
。ls
目的のファイル名の前にあることに注意してください。
最初にstripEscape関数を使用してエスケープシーケンスを削除し、次に出力をMartijnの正規表現に渡します。これにより、不要なビットの連結が回避されます。
Python 3.5を使用した2020の場合、string.encode().decode('ascii')
ascii_string = 'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'
decoded_string = ascii_string.encode().decode('ascii')
print(decoded_string)
>ls
>examplefile.zip
>