2012-03-19 1 views
4

필자는 파이썬의 유니 코드 문자열에 미쳐있을 것이라고 생각합니다. 유니 코드 문자열 에서 이스케이프 문자를 인코딩하려고 시도하고 있는데 실제 유니 코드 문자를 이스케이프 처리하지 않고 있습니다. 나는이납니다 :유니 코드를 죽이지 않고 파이썬 2에서 이스케이프 문자를 인코딩하는 올바른 방법은 무엇입니까?

In [14]: a = u"Example\n" 

In [15]: b = u"Пример\n" 

In [16]: print a 
Example 


In [17]: print b 
Пример 


In [18]: print a.encode('unicode_escape') 
Example\n 

In [19]: print b.encode('unicode_escape') 
\u041f\u0440\u0438\u043c\u0435\u0440\n 

나는 필사적으로 (영어 예, 분명히 내가 원하는대로 작동)가 필요합니다 반면 :

In [18]: print a.encode('unicode_escape') 
Example\n 

In [19]: print b.encode('unicode_escape') 
Пример\n 

어떻게해야합니까, 파이썬 3로 이동의 짧은?

추 신 : 아래에 지적했듯이 실제로 제어 문자를 벗어나려고합니다. 내가 필요로하는 것 이상을 필요로하는지는 보여야 만합니다.

+0

인코딩 할 문자는 무엇입니까? 그냥'\ r \ n \ t'? "이스케이프 문자"와 같은 것은 없습니다. – agf

+3

문제는 귀하의 요청이 역설적이라는 것입니다. Python 2 문자열 (Python 3'bytes')에는 유니 코드 문자가 포함되어 있지 않습니다. 바이트 만 포함합니다. 이 바이트는 특정 인코딩에 저장된 유니 코드 코드 포인트 일 수 있지만 여전히 바이트입니다. 유니 코드를 저장하려면 '유니 코드'를 사용하십시오. 바이트를 원한다면 바이트를 사용하십시오. 그런데 유니 코드가 없으면 UTF- *라는 정보가없는 바이트 만 있습니다. 이상한 8 비트 코드 페이지 일 수도 있습니다. 또한 통찰력과 일반적인 접근법을 제공하는 http://nedbatchelder.com/text/unipain.html을 참조하십시오. – delnan

+0

@agf 기본적으로 모든 "특수"문자입니다. 필자는 적어도 파이썬이 유니 코드 코드 포인트가 하나의 문자임을 알고 그 코드를 그대로 두길 바란다. –

답변

3

먼저 용어를 수정합시다. 당신이하려는 것은 "제어 문자"를 동등한 "이스케이프 시퀀스"로 대체하는 것입니다.

아무 것도 아직 게시하지 않은 기본 제공 방법을 찾을 수 없습니다. 다행히도 작성하는 것은 어려운 기능이 아닙니다.

control_chars = [unichr(c) for c in range(0x20)] # you may extend this as required 

def control_escape(s): 
    chars = [] 
    for c in s: 
     if c in control_chars: 
      chars.append(c.encode('unicode_escape')) 
     else: 
      chars.append(c) 
    return u''.join(chars) 

또는 약간 덜 읽을 수있는 한 줄 버전

:

def control_escape2(s): 
    return u''.join([c.encode('unicode_escape') if c in control_chars else c for c in s]) 
+0

오 예, "제어 문자"는 완전히 잊어 버렸습니다. –

+0

이제 문제는 어떻게 작성한 문자열을 디코딩합니까? 이 작업을 시도 할 때 올바른 바이트 문자열이 있지만 뒤로 이동할 수 없습니다. – underrun

+0

@underrun, 문제가 있다면 새로운 질문으로 게시해야합니다. 나는 빠른 대답이 없다. –

0

.encode('unicode_escape')는 바이트 문자열을 반환합니다. 당신은 아마 유니 코드 문자열에서 직접 제어 문자를 탈출하려는 :

# coding: utf8 
import re 

def esc(m): 
    return u'\\x{:02x}'.format(ord(m.group(0))) 

s = u'\r\t\b马克\n' 

# Match control characters 0-31. 
# Use DOTALL option to match end-of-line control characters as well. 
print re.sub(ur'(?s)[\x00-\x1f]',esc,s) 

출력 :

\x0d\x09\x08马克\x0a 

주 당신이 더 많은 일을해야 할 수 있도록 0-31 넘어 다른 유니 코드 제어 문자가있다 같은 :

# coding: utf8 
import re 
import unicodedata as ud 

def esc(m): 
    c = m.group(0) 
    if ud.category(c).startswith('C'): 
     return u'\\u{:04x}'.format(ord(c)) 
    return c 

s = u'\rMark\t\b马克\n' 

# Match ALL characters so the replacement function 
# can test the category. Not very efficient if the string is long. 
print re.sub(ur'(?s).',esc,s) 

출력 :

\u000dMark\u0009\u0008马克\u000a 

제어 문자로 간주되는 것을보다 세밀하게 제어 할 수 있습니다. 숫자는 categories입니다. 당신이 특정 유형과 일치하는 정규 표현식을 만들 수 :

import sys 
import re 
import unicodedata as ud 

# Generate a regular expression that matches any Cc category Unicode character. 
Cc_CODES = u'(?s)[' + re.escape(u''.join(unichr(n) for n in range(sys.maxunicode+1) if ud.category(unichr(n)) == 'Cc')) + u']' 
2

백 슬래시 탈출 아스키 제어 문자를 유니 코드 데이터의 중간에 확실히 달성하려고하는 유용한 일이다. 그러나 실제 문자 데이터를 되돌리려면 문자를 이스케이프 처리하는 것이 아니라 문자를 이스케이프 처리해야합니다.

파이썬 stdlib에서이를 수행하는 방법이 있어야하지만 그렇지 않습니다.

하지만 그 동안의 http://bugs.python.org/issue18679가 여기 번역 및 해커 사용하여 주변의 일이다 : 나는 버그 리포트 제출

tm = dict((k, repr(chr(k))[1:-1]) for k in range(32)) 
tm[0] = r'\0' 
tm[7] = r'\a' 
tm[8] = r'\b' 
tm[11] = r'\v' 
tm[12] = r'\f' 
tm[ord('\\')] = '\\\\' 

b = u"Пример\n" 
c = b.translate(tm) 
print(c) ## results in: Пример\n 

모든 비 백 슬래시 - 단일 문자 제어 문자가로 이스케이프됩니다 \ x ## 시퀀스를 사용하지만, 다른 작업이 필요하다면 번역 매트릭스를 사용하면됩니다. 이 접근법은 손실이 없으므로 저에게 효과적입니다.

번역을 사용하여 문자 시퀀스를 다시 단일 문자로 변환 할 수 없으므로이 코드를 다시 가져 오는 것은 엉뚱한 것입니다.

d = c.encode('latin1', 'backslashreplace').decode('unicode_escape') 
print(d) ## result in Пример with trailing newline character 

당신은 실제로 백 슬래시가 unicode_escape 코덱이 모든 것을 올바른 방법으로 재 조립 처리 할 수 ​​있도록 알지 못하는 latin1에 유니 코드 문자를 탈출하면서 개별적으로 라틴를 사용하여 바이트로 매핑 문자를 인코딩해야합니다.

UPDATE는 :

그래서 내가 python2.7과 python3.3 모두에서 작업이 필요한 경우가 있었다. 다음은 내가 한 일입니다 (_compat.py 모듈에 있음) :

if isinstance(b"", str):               
    byte_types = (str, bytes, bytearray)           
    text_types = (unicode,)              
    def uton(x): return x.encode('utf-8', 'surrogateescape')      
    def ntob(x): return x              
    def ntou(x): return x.decode('utf-8', 'surrogateescape')      
    def bton(x): return x 
else:                   
    byte_types = (bytes, bytearray)            
    text_types = (str,)               
    def uton(x): return x              
    def ntob(x): return x.encode('utf-8', 'surrogateescape')      
    def ntou(x): return x              
    def bton(x): return x.decode('utf-8', 'surrogateescape')  

escape_tm = dict((k, ntou(repr(chr(k))[1:-1])) for k in range(32))    
escape_tm[0] = u'\0'                
escape_tm[7] = u'\a'                
escape_tm[8] = u'\b'                
escape_tm[11] = u'\v'               
escape_tm[12] = u'\f'               
escape_tm[ord('\\')] = u'\\\\' 

def escape_control(s):               
    if isinstance(s, text_types):            
     return s.translate(escape_tm) 
    else: 
     return s.decode('utf-8', 'surrogateescape').translate(escape_tm).encode('utf-8', 'surrogateescape') 

def unescape_control(s):               
    if isinstance(s, text_types):            
     return s.encode('latin1', 'backslashreplace').decode('unicode_escape') 
    else:                  
     return s.decode('utf-8', 'surrogateescape').encode('latin1', 'backslashreplace').decode('unicode_escape').encode('utf-8', 'surrogateescape') 
관련 문제