Sử dụng tokenize
library để tìm kiếm token.OP
tokens, trong đó phần tử thứ hai là ;
*. Thay thế các mã thông báo này bằng token.NEWLINE
token.
Bạn cần phải điều chỉnh bù lệch mã thông báo và tạo thụt lề phù hợp quá; do đó, sau NEWLINE
bạn cần phải điều chỉnh số dòng (tăng bởi số tiền bạn tăng cho mỗi NEWLINE
bạn chèn) và dòng 'tiếp theo' (phần còn lại của dòng hiện tại) sẽ phải có các chỉ số được điều chỉnh để khớp với thụt đầu dòng hiện tại cấp:
import tokenize
TokenInfo = getattr(tokenize, 'TokenInfo', lambda *a: a) # Python 3 compat
def semicolon_to_newline(tokens):
line_offset = 0
last_indent = None
col_offset = None # None or an integer
for ttype, tstr, (slno, scol), (elno, ecol), line in tokens:
slno, elno = slno + line_offset, elno + line_offset
if ttype in (tokenize.INDENT, tokenize.DEDENT):
last_indent = ecol # block is indented to this column
elif ttype == tokenize.OP and tstr == ';':
# swap out semicolon with a newline
ttype = tokenize.NEWLINE
tstr = '\n'
line_offset += 1
if col_offset is not None:
scol, ecol = scol - col_offset, ecol - col_offset
col_offset = 0 # next tokens should start at the current indent
elif col_offset is not None:
if not col_offset:
# adjust column by starting column of next token
col_offset = scol - last_indent
scol, ecol = scol - col_offset, ecol - col_offset
if ttype == tokenize.NEWLINE:
col_offset = None
yield TokenInfo(
ttype, tstr, (slno, scol), (elno, ecol), line)
with open(sourcefile, 'r') as source, open(destination, 'w') as dest:
generator = tokenize.generate_tokens(source.readline)
dest.write(tokenize.untokenize(semicolon_to_newline(generator)))
Lưu ý rằng tôi không bận tâm sửa giá trị line
; nó chỉ mang tính thông tin, dữ liệu được đọc từ tập tin này không thực sự được sử dụng khi bỏ thông báo.
Demo:
>>> from io import StringIO
>>> source = StringIO('''\
... def main():
... a = "a;b"; return a
... ''')
>>> generator = tokenize.generate_tokens(source.readline)
>>> result = tokenize.untokenize(semicolon_to_newline(generator))
>>> print(result)
def main():
a = "a;b"
return a
và hơi phức tạp hơn:
>>> source = StringIO('''\
... class Foo(object):
... def bar(self):
... a = 10; b = 11; c = 12
... if self.spam:
... x = 12; return x
... x = 15; return y
...
... def baz(self):
... return self.bar;
... # note, nothing after the semicolon
... ''')
>>> generator = tokenize.generate_tokens(source.readline)
>>> result = tokenize.untokenize(semicolon_to_newline(generator))
>>> print(result)
class Foo(object):
def bar(self):
a = 10
b = 11
c = 12
if self.spam:
x = 12
return x
x = 15
return y
def baz(self):
return self.bar
# note, nothing after the semicolon
>>> print(result.replace(' ', '.'))
class.Foo(object):
....def.bar(self):
........a.=.10
........b.=.11
........c.=.12
........if.self.spam:
............x.=.12
............return.x
........x.=.15
........return.y
....def.baz(self):
........return.self.bar
........
........#.note,.nothing.after.the.semicolon
* Các Python 3 phiên bản của tokenize
đầu ra thông tin mới hơn TokenInfo
tên các bộ, trong đó có một phụ exact_type
thuộc tính có thể được sử dụng thay vì thực hiện so khớp văn bản: tok.exact_type == tokenize.SEMI
. Tuy nhiên, tôi đã giữ phần trên tương thích với Python 2 và 3.
Edited để thêm một số ';' s trong nhận xét và một số trường hợp bệnh lý có lặp đi lặp lại '; 'S. – PaulMcG