Форматирование строк без индекса в python2.6
У меня есть много тысяч строк кода python с форматированием строки стиля python2.7 + (например, без индексов в {} s)
"{} {}".format('foo', 'bar')
Мне нужно запустить этот код под python2.6, а python2.6 требует индексов.
Мне интересно, знает ли кто-нибудь о безболезненном пути, чтобы python2.6 мог запускать этот код. Было бы здорово, если бы проблема "из __future__ import blah" была решена. Я его не вижу. Что-то по этим линиям будет моим первым выбором.
Далекой секундой будет некоторая script, которая может автоматизировать процесс добавления индексов, по крайней мере в очевидных случаях:
"{0} {1}".format('foo', 'bar')
Ответы
Ответ 1
Он не совсем сохраняет пробелы и, вероятно, может быть немного умнее, но он, по крайней мере, будет правильно идентифицировать строки Python (апострофы/кавычки/многострочные строки), не прибегая к регулярному выражению или внешнему парсеру:
import tokenize
from itertools import count
import re
with open('your_file') as fin:
output = []
tokens = tokenize.generate_tokens(fin.readline)
for num, val in (token[:2] for token in tokens):
if num == tokenize.STRING:
val = re.sub('{}', lambda L, c=count(): '{{{0}}}'.format(next(c)), val)
output.append((num, val))
print tokenize.untokenize(output) # write to file instead...
Пример ввода:
s = "{} {}".format('foo', 'bar')
if something:
do_something('{} {} {}'.format(1, 2, 3))
Пример вывода (обратите внимание на немного пробелов):
s ="{0} {1}".format ('foo','bar')
if something :
do_something ('{0} {1} {2}'.format (1 ,2 ,3 ))
Ответ 2
Вы можете определить функцию для форматирования строк форматирования:
def reformat(s):
return "".join("".join((x, str(i), "}"))
for i, x in list(enumerate(s.split("}")))[:-1])
Ответ 3
Может быть, хороший старый sed-regex нравится:
sed source.py -e 's/{}/%s/g; s/\.format(/ % (/'
ваш пример изменился бы на что-то вроде:
"%s %s" % ('foo', 'bar')
Вы потеряли новый стиль .format()
, но он почти никогда не будет полезен для тривиальных вставок значений.
Ответ 4
Преобразование script может быть довольно простым. Вы можете найти строки для замены регулярным выражением:
fmt = "['\"][^'\"]*{}.*?['\"]\.format"
str1 = "x; '{} {}'.format(['foo', 'bar'])"
str2 = "This is a function; 'First is {}, second is {}'.format(['x1', 'x2']); some more code"
str3 = 'This doesn't have anything but a format. format(x)'
str4 = "This has an old-style format; '{0} {1}'.format(['some', 'list'])"
str5 = "'{0}'.format(1); '{} {}'.format(['x', 'y'])"
def add_format_indices(instr):
text = instr.group(0)
i = 0
while '{}' in text:
text = text.replace('{}', '{%d}'%i, 1)
i = i+1
return text
def reformat_text(text):
return re.sub(fmt, add_format_indices, text)
reformat_text(str1)
"x; '{0} {1}'.format(['foo', 'bar'])"
reformat_text(str2)
"This is a function; 'First is {0}, second is {1}'.format(['x1', 'x2']); some more code"
reformat_text(str3)
"This doesn't have anything but a format. format(x)"
reformat_text(str4)
"This has an old-style format; '{0} {1}'.format(['some', 'list'])"
reformat_text(str5)
"'{0}'.format(1); '{0} {1}'.format(['x', 'y'])"
Я думаю, вы могли бы бросить целый файл через это. Вероятно, вы можете найти более быструю реализацию add_format_indices, и, очевидно, она не была протестирована много.
Слишком плохо, что нет import __past__
, но в общем случае не что-то обычно предлагаемое (см. пример 2to3 script), так что это, вероятно, ваш следующий лучший вариант.