Python string.replace() не заменяет символы

Некоторая справочная информация: у нас есть древняя веб-система базы данных документов, где я работаю, почти полностью состоящая из документов MS Office с «обычными» расширениями (.doc, .xls, .ppt). Все они названы на основе произвольного идентификационного номера (например, 1245.doc). Мы переходим на SharePoint, и мне нужно переименовать все эти файлы и рассортировать их по папкам. У меня есть файл CSV со всевозможной информацией (например, какой идентификационный номер соответствует какому названию документа), поэтому я использую его для переименования этих файлов. Я написал короткий скрипт Python, который переименовывает заголовок идентификационного номера.

Однако в названиях некоторых документов есть косая черта и другие, возможно, недопустимые символы в заголовке файла, поэтому я хочу заменить их символами подчеркивания:

bad_characters = ["/", "\\", ":", "(", ")", "<", ">", "|", "?", "*"]
for letter in bad_characters:
    filename = line[2].replace(letter, "_")
    foldername = line[5].replace(letter, "_")
  • Пример line[2]: "Бла-бла-скучно - встреча 19.02.2008.doc"
  • Пример line[5]: "Деловые встречи 2/2008"

Когда я добавляю print letter внутрь цикла for, он распечатывает букву, которую должен заменить, но на самом деле не заменяет этот символ символом подчеркивания, как я этого хочу.

Есть ли что-то, что я делаю неправильно здесь?


person ZeroUptime    schedule 19.08.2010    source источник
comment
Касательный вопрос: рассматривали ли вы возможность сделать это с помощью регулярного выражения?   -  person Manoj Govindan    schedule 19.08.2010
comment
@all - Спасибо за объяснения. Не могу поверить, что я проглядел это. (по четвергам...)   -  person ZeroUptime    schedule 19.08.2010


Ответы (5)


Это потому, что filename и foldername выбрасываются с каждой итерацией цикла. Метод .replace() возвращает строку, но вы никуда не сохраняете результат.

Вы должны использовать:

filename = line[2]
foldername = line[5]

for letter in bad_characters:
    filename = filename.replace(letter, "_")
    foldername = foldername.replace(letter, "_")

Но я бы сделал это с помощью регулярного выражения. Это чище и (вероятно) быстрее:

p = re.compile('[/:()<>|?*]|(\\\)')
filename = p.sub('_', line[2])
folder = p.sub('_', line[5])
person NullUserException    schedule 19.08.2010
comment
Может быть причина не менять строку[2] и строку[5] - person Kathy Van Stone; 19.08.2010

Вы переназначаете переменные filename и foldername на каждой итерации цикла. Фактически заменяется только *.

person Vebjorn Ljosa    schedule 19.08.2010

Вы должны посмотреть на строковый метод python translate() http://docs.python.org/library/string.html#string.translate с http://docs.python.org/library/string.html#string.maketrans

Editing this to add an example as per comment suggestion below:
import string
toreplace=''.join(["/", "\\", ":", "(", ")", "<", ">", "|", "?", "*"]) 
underscore=''.join( ['_'] * len(toreplace))
transtable = string.maketrans(toreplace,underscore)
filename = filename.translate(transtable)
foldername = foldername.translate(transtable)

Можно упростить, сделав для замены что-то вроде '/\:' и т. д., я просто использовал то, что было дано выше.

person Amala    schedule 19.08.2010
comment
не могли бы вы привести пример в текущем контексте? - person iamgopal; 19.08.2010

Вы начинаете с базовой линии вместо сохранения замененного результата, таким образом, вы получаете эквивалент

filename = line[2].replace('*', '_')
foldername = line[5].replace('*', '_')

Попробуйте следующее

bad_characters = ["/", "\\", ":", "(", ")", "<", ">", "|", "?", "*"]
filename = line[2]
foldername = line[5]
for letter in bad_characters:
    filename = filename.replace(letter, "_")
    foldername = foldername.replace(letter, "_")
person Kathy Van Stone    schedule 19.08.2010

Следует использовать string.replace(str, fromStr, toStr)

bad_characters = ["/", "\\", ":", "(", ")", "<", ">", "|", "?", "*"]
for letter in bad_characters:
    filename = string.replace(line[2], letter, "_")
    foldername = string.replace(line[5], letter, "_")
person wu liang    schedule 18.08.2011