2015-06-01 25 views
5

我想製作一個包含不可打印字符的文件,僅包含可打印字符。我認爲這個問題與ACSCII control action有關,但我找不到解決方案來做到這一點,也無法理解.[16D(ASCII控制動作字符??)在以下文件中的含義。如何僅過濾Bash(linux)或Python文件中的可打印字符?

進制打印輸入文件:

00000000: 4845 4c4c 4f20 5448 4953 2049 5320 5448 HELLO THIS IS TH 
00000010: 4520 5445 5354 1b5b 3136 4420 2020 2020 E TEST.[16D 
00000020: 2020 2020 2020 2020 2020 201b 5b31 3644   .[16D 
00000030: 2020 

當我cat版上bash文件,我剛: 「HELLO」。我認爲這是因爲默認cat解釋那個ASCII控制動作,兩個.[16D s。

爲什麼兩個.[16D字符串會使cat FILE只是爲了打印「HELLO」?,而且......我如何才能讓該文件包含可打印字符,即「HELLO」?

+0

你試過string.printable嗎? – therealprashant

+0

我想知道爲什麼Python標籤.... – 0xc0de

+0

在大多數* nix系統上,當然在任何GNU系統上,應該有一個[strings](http://linux.die.net/man/1/strings)命令。 –

回答

2

的hexdump都表明,在.[16D點實際上是一個轉義字符,\x1b
Esc[nDANSI escape code刪除n個字符。所以Esc[16D告訴終端刪除16個字符,這說明了cat輸出。

有多種方法可以使用Bash命令(例如使用sed,如Anubhava的答案)或Python來從文件中刪除ANSI轉義代碼。

然而,在這樣的情況下,它可能是更好的通過終端模擬器來運行該文件來解釋任何現有的編輯控制序列的文件,這樣你就應用了這些編輯序列後,他們得到的結果文件的作者的意圖。

在Python中執行該操作的一種方法是使用pyte,這是一個實現簡單的VTXXX兼容終端仿真器的Python模塊。您可以使用pip輕鬆進行安裝,以下是readthedocs上的文檔。

下面是一個簡單的演示程序,用於解釋問題中給出的數據。它是爲Python 2編寫的,但很容易適應Python 3.​​支持Unicode,它的標準Stream類需要Unicode字符串,但本例使用ByteStream,所以我可以將它傳遞給普通字節字符串。

#!/usr/bin/env python 

''' pyte VTxxx terminal emulator demo 

    Interpret a byte string containing text and ANSI/VTxxx control sequences 

    Code adapted from the demo script in the pyte tutorial at 
    http://pyte.readthedocs.org/en/latest/tutorial.html#tutorial 

    Posted to http://stackoverflow.com/a/30571342/4014959 

    Written by PM 2Ring 2015.06.02 
''' 

import pyte 


#hex dump of data 
#00000000 48 45 4c 4c 4f 20 54 48 49 53 20 49 53 20 54 48 |HELLO THIS IS TH| 
#00000010 45 20 54 45 53 54 1b 5b 31 36 44 20 20 20 20 20 |E TEST.[16D  | 
#00000020 20 20 20 20 20 20 20 20 20 20 20 1b 5b 31 36 44 |   .[16D| 
#00000030 20 20            | | 

data = 'HELLO THIS IS THE TEST\x1b[16D    \x1b[16D ' 

#Create a default sized screen that tracks changed lines 
screen = pyte.DiffScreen(80, 24) 
screen.dirty.clear() 
stream = pyte.ByteStream() 
stream.attach(screen) 
stream.feed(data) 

#Get index of last line containing text 
last = max(screen.dirty) 

#Gather lines, stripping trailing whitespace 
lines = [screen.display[i].rstrip() for i in range(last + 1)] 

print '\n'.join(lines) 

輸出輸出

HELLO 

十六進制轉儲

00000000 48 45 4c 4c 4f 0a         |HELLO.| 
+0

感謝您的標記。但是對另一個文件的貓FILE只是FILE的一個副本,其中也包含了不可打印的字符。我已經試過了......你有另一種解決方案嗎?.. – freddy

+0

對不起@freddy。我應該意識到'貓'不會清理那些控制序列。我目前正在努力尋找可以完成這項工作的_something_,但我今天晚上可能找不到解決方案。 –

+0

@freddy:FWIW,簡單地擺脫任何ANSI序列,比如'ESC [nD'不是太難,在OP的例子中會給你'你好,這就是測試'。你想要那個,還是你想要簡單的'HELLO'? –

1

你可以試試這個sed命令從文件中刪除所有非打印字符:

sed -i.bak 's/[^[:print:]]//g' file 
+2

這是正確的,但要注意什麼是可打印和什麼不取決於區域設置。 – lcd047

+0

是的,這取決於區域設置。 – anubhava

0

簡約的解決方案在我腦海中是

import string 
printable_string = filter(lambda x: x in string.printable, your_string) 
## TODO: substitute your string in the place of "your_string" 

如果仍不能解決問題,然後嘗試還包括單向特定代碼[curses.ascii]

0

見內建string模塊。

import string 
printable_str = filter(string.printable, string)