2013-09-21 5 views
1

У меня есть дата, указанная в формате «28 октября 2010» (или simillar). Теперь я хочу изменить полное название месяца на более короткую версию (в этом случае Oct). Для этого я подготовил словарь:Странное поведение при замене строки в python

_mapping = {'January': 'Jan', 
      'February': 'Feb', 
      'March': 'Mar', 
      'April': 'Apr', 
      'May': 'May', 
      'June': 'Jun', 
      'July': 'Jul', 
      'August': 'Aug', 
      'September': 'Sep', 
      'October': 'Oct', 
      'November': 'Nov', 
      'December': 'Dec'} 

и в методе, где substition идет, я написал следующее:

def fetch(self, pno): 
    ... 
    date = #get data (working fine) 
    for l, s in self._mapping.iteritems(): 
     pubdate = date.replace(l, s) 
     print l + " -> " + pubdate #this is only for debug 
    (pubd_month, self.pubd_day, self.pubd_year) = pubdate.split(' ') 
    print pubd_month, self.pubd_day, self.pubd_year 
    print pubdate 

Результат исполнения является:

February -> October 28, 2008 
October -> Oct 28, 2008 
January -> October 28, 2008 
April -> October 28, 2008 
November -> October 28, 2008 
March -> October 28, 2008 
August -> October 28, 2008 
May -> October 28, 2008 
December -> October 28, 2008 
June -> October 28, 2008 
September -> October 28, 2008 
July -> October 28, 2008 
October 
October 28, 2008 

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

Другой вопрос: существует ли более короткий способ сделать это?

ответ

3

_mapping не требуется. Если вы используете datetime.datetime объектов, метод strftime может возвратить сокращенный месяц для вас:

import datetime as DT 

def short_date(date): 
    date = DT.datetime.strptime(date, '%B %d, %Y') 
    return date.strftime('%b %d, %Y') 

print(short_date('October 28, 2010')) 

печатает

Oct 28, 2010 

Если дата строка приходит в различных форматах, то вместо разбора их strptime(date, '%B %d, %Y') вы может использовать метод dateutil parser.parse. Для максимальной гибкости вам, вероятно, лучше всего будет синтаксический анализ строк даты в datetime.datetime объектам как можно раньше и с помощью strftime, чтобы отформатировать их как можно позже.

+0

Обратите внимание, что имена месяцев '% b' и'% B' зависят от локали. Я обнаружил, что если ваш код должен работать в разных средах, где вы не контролируете локаль, вы должны вручную выполнять месячные замены * в любом случае *. –

+0

Можно ли принудительно использовать английский язык? – Moby04

+0

Не совсем; Честно говоря, гораздо проще просто заменить струны. См. [Форматирование даты в Python] (http://stackoverflow.com/q/985505) для решения, которое * может * работать в системах POSIX при условии, что локаль была сгенерирована. –

3

Потому что вы всегда замена pubdate с заменой на date, вы перезаписать успешное согласование.

Либо тест первым, если месяц в строке перед тем замены или заменить pubdate с pubdate.replace() результатами:

pubdate = #get data (working fine) 
for l, s in self._mapping.iteritems(): 
    pubdate = pubdate.replace(l, s) 

или, с помощью тестирования:

date = #get data (working fine) 
for l, s in self._mapping.iteritems(): 
    if l in date: 
     pubdate = date.replace(l, s) 

Последние еще приведет к тому, что pubdate будет перезаписано, если найдено более одного месяца. С другой стороны, если есть только когда-либо будет один месяц матч, используйте break, чтобы закончить цикл рано:

date = #get data (working fine) 
for l, s in self._mapping.iteritems(): 
    if l in date: 
     pubdate = date.replace(l, s) 
     break 

Оговорка: если не матч не будет найдено, pubdate никогда не был назначен и вы получите исключение UnboundLocal.

+0

Да, глупая ошибка. Спасибо :) Однако, хотя в этой конкретной ситуации решение ubutbu чище, поэтому я буду отмечать его как принято. – Moby04

Смежные вопросы