2012-11-22 54 views
0

我試圖找出一種方式來編碼/解碼二進制數據,使得新行字符不是編碼字符串的一部分。編碼二進制數據,以便 n逃脫

這似乎是一個遞歸問題,但我似乎無法找到解決方案。

例如天真的執行:

>>> original = 'binary\ndata' 

>>> encoded = original.replace('\n', '=n') 
'binary=ndata' 
>>> decoded = original.replace('=n', '\n') 
'binary\ndata' 

如果原始字符串中已經有=n會發生什麼?

>>> original = 'binary\ndata=n' 

>>> encoded = original.replace('\n', '=n') 
'binary=ndata=n' 
>>> decoded = original.replace('=n', '\n') 
'binary\ndata\n' # wrong 

試圖逃跑現有=n的,但這時如果已經有一個逃脫=n會發生什麼?

>>> original = '++nbinary\ndata=n' 

>>> encoded = original.replace('=n', '++n').replace('\n', '=n') 
'++nbinary=ndata++n' 

我該如何解決這個遞歸問題?

+0

出了什麼問題[Base64編碼(http://en.wikipedia.org/wiki/Base64)? –

+0

@DourHighArch編碼值的大小很重要。 Base64的開銷約爲33%。我需要將它縮小爲與原始尺寸相似。 –

+0

你爲什麼「需要」那個? [〜25%的開銷](http://en.wikipedia.org/wiki/Base85)如何?輸出是否必須是ASCII?爲什麼換行符不可接受?這聽起來像是一個XY問題;你需要告訴我們這些奇怪的要求來自哪裏。 –

回答

0

如果你係統地編碼了整個字符串,你會不會最終逃脫它?對於每個你做過字符(ord(char)+ 1)的人來說,還是像那樣的小事?

+0

如果原始字符串中有一個chr(ord('\ n') - 1)會怎麼樣?編碼的字符串不會在其中包含「\ n」嗎? –

+0

啊,好的。所以是的,我想不出一個聰明的方式來不使用一個你根本就沒有映射到任何東西的角色。 *接受失敗* –

0

我對二進制數據沒有太多的經驗,所以這可能完全關閉/低效/兩者,但是這會解決您的問題嗎?

In [40]: original = 'binary\ndata\nmorestuff' 

In [41]: nlines = [index for index, i in enumerate(original) if i == '\n'] 

In [42]: encoded = original.replace('\n', '') 

In [43]: encoded 
Out[43]: 'binarydatamorestuff' 

In [44]: decoded = list(encoded) 

In [45]: map(lambda x: decoded.insert(x, '\n'), nlines) 
Out[45]: [None, None] 

In [46]: decoded = ''.join(decoded) 

In [47]: decoded 
Out[47]: 'binary\ndata\nmorestuff' 

同樣,我確信有一個更好/更準確的方法 - 這只是從新手的角度。

+0

有趣的想法。缺少一個步驟 - 您還需要對編碼字符串中的位置進行編碼。 –

+0

@GeraldKaszuba那麼編碼後期望的行爲是什麼?同意這是一個有趣的問題:) – RocketDonkey

+0

基本上編碼的字符串必須存儲能夠解碼它所需的所有信息,例如,將其保存到文件中。在您的示例中,您正在使用「額外」信息在Python中存儲變量以幫助解碼,但當另一個進程嘗試解碼文件時,無法使用該信息。我希望這解釋更多一點:) –

1

對可能包含「轉義」字符的字符串進行編碼的方式也是轉義轉義字符。在Python中,轉義字符是一個反斜槓,但你可以使用任何你想要的。每次換行或逃生時,您的成本都是一個字符。

爲了避免混淆你,我將使用正斜槓:

# original 
>>> print "slashes/and /newline/\nhere" 
slashes/and /newline/ 
here 
# encoding 
>>> print "slashes/and /newline/\nhere".replace("/", "//").replace("\n", "/n") 
slashes // and //newline///nhere 

這種編碼是唯一的,由於所有真正斜槓一倍;但它必須在單次被解碼,所以你不能只是用它來replace()兩個連續通話:

# decoding 
>>> def decode(c): 
    # Expand this into a real mapping if you have more substitutions 
    return '\n' if c == '/n' else c[0] 

>>> print "".join(decode(c) for c in re.findall(r"(/.|.)", 
             "slashes // and //newline///nhere")) 
slashes/and /newline/ 
here 

注意,有輸入實際/n(和換行符之前的另一個斜槓):它無論如何所有工作都正常。

+0

如果原始字符串中有「/ n」,該怎麼辦? –

+0

糟糕!編碼很好,但需要一次解碼。看到更正的答案。 – alexis

0

如果您將n個符號(例如ASCII)的字母表編碼爲更小的一組m個符號(例如ASCII,除了換行符),您必須允許編碼字符串比原始字符串長。

這樣做的典型方法是將一個字符定義爲「逃逸」字符; 「逃逸」後面的字符表示編碼字符。自20世紀40年代以來,這種技術已被用於電傳打字機;這就是您在鍵盤上看到的「Esc」鍵的來源。

Python(和其他語言)已經在字符串中使用反斜槓字符。換行符編碼爲'\ n'(或'\ r \ n')。反斜槓自行逃脫,所以字符串'\ r \ n'將被編碼爲'\\ r \\ n'。

請注意,只包含轉義字符的字符串的編碼長度將是原始字符串的兩倍。如果這是不可接受的,您將不得不使用使用較大字母表的編碼來避免轉義字符(可能比原始字符串更長)或壓縮它(也可能比原始字符串更長)。

1

解決方案

original = 'binary\ndata \\n' 
# encoded = original.encode('string_escape')     # escape many chr 
encoded = original.replace('\\', '\\\\').replace('\n', '\\n') # escape \n and \\ 
decoded = encoded.decode('string_escape') 

驗證

>>> print encoded 
binary\ndata \\n 
>>> print decoded 
binary 
data \n 

的解決方案是從How do I un-escape a backslash-escaped string in python?

編輯:我寫這也與你的ad-hoc經濟編碼。原始的「string_escape」編解碼器可以轉義反斜槓,撇號以及chr(32)和chr(126)以上的所有內容。兩者的解碼都是一樣的。

+0

好主意。我玩過string_escape,但沒想到只用它來解碼。 –

0

如何:

In [8]: import urllib 

In [9]: original = 'binary\ndata' 

In [10]: encoded = urllib.quote(original) 

In [11]: encoded 
Out[11]: 'binary%0Adata' 

In [12]: urllib.unquote(encoded) 
Out[12]: 'binary\ndata' 
+0

'urllib.quote'轉義其他字符。這個問題專門針對'\ n'轉義。 –