1

特定の方法で印刷したい月のカレンダーアイテムの辞書(日付が「キー」、リスト形式のアイテムdctが「値」)があります(その辞書はコードに含まれ、に割り当てられます)。現在の日付以降(つまり今日) のアイテムのみ表示したい。表示形式は次のとおりです。

day: item1, item2

また、これらの項目が stdout の 5 行にまたがり、各行が 49 文字幅 (スペースを含む) になるようにしたいと考えています。出力がconky(Linux用アプリ)に表示されるため、これが必要です。

1 日には複数のアジェンダ アイテムが含まれる可能性があるため、出力は複数の行に折り返されて印刷される必要があります。関連する項目が 5 行を超える 5 日を印刷するのではなく、項目が 5 行以下に収まる日のみを選択することで、コードでそれを考慮したいと考えています。例えば

day1: item1, item2
      item3
day2: item1
day3: item1,
      item2

これは、各行が 49 文字幅の 5 行に印刷された当日から 3 日後です。49 文字を超える文字列は改行で折り返されます。

これを行うために私が書いたコードは次のとおりです。

#!/usr/bin/env python

from datetime import date, timedelta, datetime
import heapq
import re
import textwrap

pattern_string = '(1[012]|[1-9]):[0-5][0-9](\\s)?(?i)(am|pm)'
pattern = re.compile(pattern_string)

# Explanation of pattern_string:
# ------------------------------
#(              #start of group #1
 #1[012]                #  start with 10, 11, 12
 #|             #  or
 #[1-9]             #  start with 1,2,...9
#)              #end of group #1
 #:             #   follow by a semi colon (:)
  #[0-5][0-9]           #     follw by 0..5 and 0..9, which means 00 to 59
            #(\\s)?     #       follow by a white space (optional)
                  #(?i)     #         next checking is case insensitive
                      #(am|pm)  #           follow by am or pm
# The 12-hour clock format is start from 0-12, then a semi colon (:) and follow by 00-59 , and end with am or pm.
# Time format that match:
# 1. "1:00am", "1:00 am","1:00 AM" ,
# 2. "1:00pm", "1:00 pm", "1:00 PM",
# 3. "12:50 pm"

d = date.today() # datetime.date(2013, 8, 11)
e = datetime.today() # datetime.datetime(2013, 8, 11, 5, 56, 28, 702926)
today = d.strftime('%a %b %d') # 'Sun Aug 11'

dct = {
'Thu Aug 01' : [' Weigh In'], 
'Thu Aug 08' : [' 8:00am', 'Serum uric acid test', '12:00pm', 'Make Cheesecake'], 
'Sun Aug 11' : [" Awais chotu's birthday", ' Car wash'], 
'Mon Aug 12' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 15' : [" Hooray! You're Facebook Free!", '10:00am', 'Start car for 10 minutes'], 
'Mon Aug 19' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 22' : ['10:00am', 'Start car for 10 minutes'], 
'Mon Aug 26' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 29' : ['10:00am', 'Start car for 10 minutes']
}

def join_time(lst):
    '''Searches for a time format string in supplied list and concatenates it + the event next to it as an single item
       to a list and returns that list'''
    mod_lst = []
    for number, item in enumerate(lst):
        if re.search(pattern, item):
            mod_lst.append(item + ' ' + lst[number+1]) # append the item (i.e time e.g '1:00am') and the item next to it (i.e. event)
            del lst[number+1]
        else:
            mod_lst.append(item)
    return mod_lst

def parse_date(datestring):
    return datetime.strptime(datestring + ' ' + str(date.today().year), "%a %b %d %Y") # returns a datetime obj for the time string; "Sun Aug 11" = datetime.datetime(1900, 8, 11, 0, 0)

deltas = [] # holds datetime.timedelta() objs; timedelta(days, seconds, microseconds)
val_len = []
key_len = {}

for key in dct:
    num = len(''.join(item for item in dct[key]))
    val_len.append(num) # calculate the combined len of all items in the 
                        # list which are the val of a key and add them to val_len
    if num > 37:
        key_len[key] = 2
    else:
        key_len[key] = 1

# val_len = [31, 9, 61, 31, 31, 49, 31, 32, 31]
# key_len = {'Sun Aug 11': 1, 'Mon Aug 12': 1, 'Thu Aug 01': 1, 'Thu Aug 15': 2, 'Thu Aug 22': 1, 'Mon Aug 19': 1, 'Thu Aug 08': 2, 'Mon Aug 26': 1, 'Thu Aug 29': 1}

counter = 0
for eachLen in val_len:
    if eachLen > 37:
        counter = counter + 2
    else:
        counter = counter + 1

# counter = 11

if counter > 5: # because we want only those 5 events in our conky output which are closest to today
    n = counter - 5 # n = 6, these no of event lines should be skipped

    for key in dct:
        deltas.append(e - parse_date(key)) # today - key date (e.g. 'Sun Aug 11') ---> datetime.datetime(2013, 8, 11, 5, 56, 28, 702926) - datetime.datetime(1900, 8, 11, 0, 0)

    # TODO: 'n' no of event lines should be skipped, NOT n no of days!  
    for key in sorted(dct, key=parse_date): # sorted() returns ['Thu Aug 01', 'Thu Aug 08', 'Sun Aug 11', 'Mon Aug 12', 'Thu Aug 15', 'Mon Aug 19', 'Thu Aug 22', 'Mon Aug 26', 'Thu Aug 29']
        tdelta = e - parse_date(key)
        if tdelta in heapq.nlargest(n, deltas): # heapq.nlargest(x, iterable[, key]); returns list of 'x' no. of largest items in iterable
            pass                                # In this case it should return a list of top 6 largest timedeltas; if the tdelta is in 
                                                # that list, it means its not amongst the 5 events we want to print
        else:
            if key == today:
                value = dct[key]
                val1 = '${color green}' + key + '$color: ' 
                mod_val = join_time(value) 
                val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
                print val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
            else:
                value = dct[key]
                mod_val = join_time(value)
                output = key + ': ' + ', '.join(item for item in mod_val)
                print '\n           '.join(textwrap.wrap(output, 49))

else:   
    for key in sorted(dct, key=parse_date):
        if key == today:
            value = dct[key]
            val1 = '${color green}' + key + '$color: ' 
            mod_val = join_time(value) 
            val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
            print val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
        else:
            value = dct[key]
            mod_val = join_time(value)
            output = key + ': ' + ', '.join(item for item in mod_val)
            print '\n           '.join(textwrap.wrap(output, 49))

結果は次のとおりです。

Thu Aug 22: 10:00am Start car for 10 minutes
Mon Aug 26: 10:00am Start car for 10 minutes
Thu Aug 29: 10:00am Start car for 10 minutes

コードにかなりのコメントを付けたので、それがどのように機能するかを理解するのは難しくありません。私は基本的に、日時を使用して現在の日から最も遠い日を計算し、それらの日とそのアイテムをスキップしています。コードは通常はうまく機能しますが、たまにうまくいかないことがあります。この場合、出力は次のようになります。

Mon Aug 19: 10:00am Start car for 10 minutes
Thu Aug 22: 10:00am Start car for 10 minutes
Mon Aug 26: 10:00am Start car for 10 minutes
Thu Aug 29: 10:00am Start car for 10 minutes

これらは当日 (8 月 16 日金曜日) の後の日であり、項目は 5 行に収まります。今日から何日も離れているのではなく、何行もスキップするように修正するにはどうすればよいですか?n

key_lendict を使用して、アイテムの長さの合計が < または = 5 になる日のアイテムのみを出力することで、出力をさらにフィルタリングすることを考えていました...

私は立ち往生しています。

4

1 に答える 1

1

ここで何を求めているのかを伝えるのは非常に難しく、コードは非常に混乱しています。

ただし、指定された例で間違った出力が得られる理由は非常に明白でありTODO、コード内のコメントと一致するため、質問している部分はそれだけであると想定します。

 # TODO: 'n' no of event lines should be skipped, NOT n no of days!

最初の 5 行ではなく、今日以降の最後の5 行にスキップする理由がわかりませんが、それには何らかの正当な理由があると思います。

これを解決する最も簡単な方法は、それらを逆に実行し、行をprint直接 ing する代わりに文字列の先頭に追加し、5 行に達したら停止して、文字列を出力することです。(これにより、無駄なヒープの再構築を何度も行う必要がなくなります。)

たとえば、次のようなものです。

outlines = []
for key in sorted(dct, key=parse_date, reverse=True): # sorted() returns ['Thu Aug 01', 'Thu Aug 08', 'Sun Aug 11', 'Mon Aug 12', 'Thu Aug 15', 'Mon Aug 19', 'Thu Aug 22', 'Mon Aug 26', 'Thu Aug 29']
    if parse_date(key) < parse_date(today):
        break
    tdelta = e - parse_date(key)
    if key == today:
        value = dct[key]
        val1 = '${color green}' + key + '$color: ' 
        mod_val = join_time(value) 
        val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
        outstr = val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
        outlines[:0] = outstr.splitlines()
    else:
        value = dct[key]
        mod_val = join_time(value)
        output = key + ': ' + ', '.join(item for item in mod_val)
        outstr = '\n           '.join(textwrap.wrap(output, 49))
        outlines[:0] = outstr.splitlines()
    if len(outlines) >= 5:
        break
print '\n'.join(outlines)

これを単純化する方法はたくさんあります。たとえば、日付の文字列表現を渡してあちこちで使用する代わりに、日付をparse_date渡して最後に一度書式設定します。120 文字の複数連結式ではなく、文字列の書式設定を使用します。必要な場所で何度も再構築するのではなく、一度データ構造を構築して使用します。等々。しかし、これが機能するために必要なすべてです。

于 2013-08-17T01:45:01.617 に答える