2013-03-16 1 views
3

나는 상당히 큰 파이썬 코드 기반을 가지고있다. 일부 문자열 리터럴은 문자열이고 다른 문자열 리틀은 유니 코드입니다. 그리고 이로 인해 버그가 발생합니다. 모든 것을 유니 코드로 변환하려고합니다. 모든 리터럴을 유니 코드로 변환 할 수있는 도구가 있는지 궁금합니다. 나는.모든 문자열 리터럴이 파이썬에서 유니 코드인지 확인하는 방법

print "result code %d" % result['code'] 

에 :

print u"result code %d" % result[u'code'] 

그것이 내가 PyCharm를 사용하는 데 도움이 경우 그러나 나는를 사용하는 것이 행복 할 것입니다, (경우에이 작업을 수행 확장이)가 이런 식으로 뭔가를 발견하는 경우 명령도 좋아요. 바라건대 그런 도구가 존재하기를 바랍니다.

+1

W |

import re scode = ''' print "'Hello World'" # prints 'Hello World' u'Unicode is unchanged'""" # so are "comments"''' x1 = re.compile('''(?P<unicode>u?)(?P<c>'|")(?P<data>.*?)(?P=c)''') def repl(m): return "u%(c)s%(data)s%(c)s" % m.groupdict() fcode = '\n'.join( [re.sub(x1,repl,i) if not '#' in i else re.sub(x1,repl,i[:i.find('#')])+i[i.find('#'):] for i in scode.splitlines()]) print fcode 

출력은 : #를 들어

print u"'Hello World'" # prints 'Hello World' u'Unicode is unchanged' # so are "comments" 

나는 (그리고 더 이상 @ unutbu의 솔루션에 비해입니다)이 있습니다 하이 "u"결과 코드 % d "'? – unutbu

+0

당신은 항상 파이썬 3을 사용할 수 있습니다 :) – MattDMo

+0

@unutbu 당신은 절대적으로 옳습니다. 나는 그것을 포함시키기 위해 질문을 편집했다. 바보 나. – mmopy

답변

7

tokenize.generate_tokens을 사용하면 파이썬 코드의 문자열 표현을 토큰으로 구분할 수 있습니다. tokenize은 토큰을 분류합니다. 따라서 파이썬 코드에서 문자열 리터럴을 식별 할 수 있습니다. 원하는 곳

'u' 추가 토큰을 조작 한 후 어렵지 않다 :


import tokenize 
import token 
import io 
import collections 

class Token(collections.namedtuple('Token', 'num val start end line')): 
    @property 
    def name(self): 
     return token.tok_name[self.num] 

def change_str_to_unicode(text):  
    result = text.splitlines() 
    # Insert a dummy line into result so indexing result 
    # matches tokenize's 1-based indexing 
    result.insert(0, '') 
    changes = [] 
    for tok in tokenize.generate_tokens(io.BytesIO(text).readline): 
     tok = Token(*tok) 
     if tok.name == 'STRING' and not tok.val.startswith('u'): 
      changes.append(tok.start) 

    for linenum, s in reversed(changes): 
     line = result[linenum] 
     result[linenum] = line[:s] + 'u' + line[s:] 
    return '\n'.join(result[1:]) 

text = '''print "result code %d" % result['code'] 
# doesn't touch 'strings' in comments 
'handles multilines' + \ 
'okay' 
u'Unicode is not touched' 
''' 

print(change_str_to_unicode(text)) 

수율

print u"result code %d" % result[u'code'] 
# doesn't touch 'strings' in comments 
u'handles multilines' + u'okay' 
u'Unicode is not touched' 
+0

이것은 훌륭했습니다. 이 답변을 함께 해주셔서 감사드립니다. – mmopy

+0

당신은 훌륭합니다. – bgusach

2

를이 (정규식 사용) 시도하며 @ unutbu 년대보다 짧다 해결책.
루프 홀이 있는데, #이 포함 된 문자열은 이와 함께 작동하지 않습니다.

import re 
scode = '''print "'Hello World'" # prints 'Hello World' 
u'Unicode is unchanged' 
# so are "comments" 
'#### Hi' # 'Hi' ''' 

x1 = re.compile('''(?P<unicode>u?)(?P<c>'|")(?P<data>.*?)(?P=c)''') 

def in_string(text,index): 
    curr,in_l,in_str,level = '',0,False,[] 

    for c in text[:index+1]: 
     if c == '"' or c == "'": 
      if in_str and curr == c: 
       instr = False 
       curr = '' 
       in_l -= 1 
      else: 
       instr = True 
       curr = c 
       in_l += 1 
     level.append(in_l) 
    return bool(level[index]) 

def repl(m): 
    return "u%(c)s%(data)s%(c)s" % m.groupdict() 

def handle_hashes(i): 
    if i.count('#') == 1: 
     n = i.find('#') 
    else: 
     n = get_hash_out_of_string(i) 
    return re.sub(x1,repl,i[:n]) + i[n:] 

def get_hash_out_of_string(i): 
    n = i.find('#') 
    curr = i[:] 
    last = (len(i)-1)-''.join(list(reversed(i))).find('#') 
    while in_string(curr,n) and n < last: 
     curr = curr[:n]+' '+curr[n+1:] 
     n = curr.find('#') 
    return n 

fcode = '\n'.join(
    [re.sub(x1,repl,i) 
    if not '#' in i 
    else handle_hashes(i) 
    for i in scode.splitlines()]) 

print fcode 

출력 :

print u"'Hello World'" # prints 'Hello World' 
u'Unicode is unchanged' 
# so are "comments" 
u'#### Hi' # 'Hi' 
관련 문제