I got this string...
String = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
I want to get the first 4 numbers (-268, 14, 7, 19) in integer-variables and Fri Aug 3 12:32:08 in another string-variable.
Is that possible?
Using basic python
string = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
vals, date = string.strip().split(' - ')
int_vals = [int(v) for v in vals.split()]
print(int_vals) # [-268, 14, 7, 19]
print(date) # Fri Aug 3 12:32:08 2018
Using regex
import re
match = re.search(r'([-\d]+) ([-\d]+) ([-\d]+) ([-\d]+)[ -]*(.*)', string)
date = match.group(5)
int_vals = [int(v) for v in match.groups()[:4]] # same results
Use str.split
Ex:
String = '-268 14 7 19 - Fri Aug 3 12:32:08 2018\n'
first, second = String.split(" - ")
first = tuple(int(i) for i in first.split())
print(first)
print(second)
Output:
(-268, 14, 7, 19)
Fri Aug 3 12:32:08 2018
Use split and map for it:
left, date = String.split(' - ')
numbers = list(map(int, left.split()))
print(numbers, date)
Related
I want to print a calendar of the current month but starting from today's date in python. Is there any way I can do this?
Only thing I thought to try was :
import calendar
y = int(input("Input the year : "))
m = int(input("Input the month : "))
d = int (input("Input the day: "))
print(calendar.month(y, m, d))
which in retrospect is a dumb idea because all it did was :
but considering my 3 day experience in python it seemed dumb enough to work.
I want the end result to look something like this:
Essentially,I want the calendar to show only the remaining days of the month,instead of the whole month.
The calender method returns a string. You can use conventual string manipulation methods to modify the string before printing - f.e. regex replacement:
import calendar
import re
y = 2020
m = 5
d = 15
h = calendar.month(y, m, 3) # 3 is the width of the date column, not the day-date
print(h)
print()
# replace all numbers before your day, take care of either spaces or following \n
for day in range(d):
# replace numbers at the start of a line
pattern = rf"\n{day} "
h = re.sub(pattern, "\n " if day < 10 else "\n ", h)
# replace numbers in the middle of a line
pattern = rf" {day} "
h = re.sub(pattern, " " if day < 10 else " ", h)
# replace numbers at the end of a line
pattern = rf" {day}\n"
h = re.sub(pattern, " \n" if day < 10 else " \n", h)
print(h)
Output:
May 2020
Mon Tue Wed Thu Fri Sat Sun
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
# after replacement
May 2020
Mon Tue Wed Thu Fri Sat Sun
15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
I have a list element which is text.
print ((temp_list))
Output:
['root pts/3 100.121.17.73 Tue Aug 7 14:22 - 14:23 (00:00) ']
I wish to get this output:
Aug 7 14:23
I have tried to remove the whitespace but that messes up the output, which makes it harder to separate out the elements I want.
You can split the text and get the 5th, 6th and 9th fields:
f = temp_list[0].split()
print(' '.join((f[4], f[5], f[8])))
Using Regex.
import re
temp_list = ['root pts/3 100.121.17.73 Tue Aug 7 14:22 - 14:23 (00:00) ']
for i in temp_list:
m = re.search(r"(?P<date>(Jun|Jul|Aug|Sep).*?)\(", i)
if m:
print(m.group('date'))
Output:
Aug 7 14:22 - 14:23
sample = 'root pts/3 100.121.17.73 Tue Aug 7 14:22 - 14:23 (00:00) '
# split the string on space characters
data = sample.split(' ')
# inspect our list in console, the list should now contain mix of words and spaces (empty string)
print(data)
# since empty string evaluates to False in Python, we can remove them like this from our list with filter function
data = filter(lambda x: x, data)
# outputs: ['root', 'pts/3', '100.121.17.73', 'Tue', 'Aug', '7', '14:22', '-', '14:23', '(00:00)']
print(data)
# in the end we collect relevant data by slicing the list
# from index 3rd to 6th and join them into one string with that data separated by one space in-between.
result = ' '.join(data[3:6])
# outputs: Tue Aug 7
print(result)
If you always have the kind of pattern 'Tue Aug 7 14:22 - 14:23' in your string, then I suggest you using regex to match this pattern:
import re
temp_list = ['root pts/3 100.121.17.73 Tue Aug 7 14:22 - 14:23 (00:00) ']
m = re.search(r'\w{3} +(\w{3}) +(\d{1,2}) +\d\d:\d\d +- +(\d\d:\d\d)', temp_list[0])
result = ' '.join([m.group(i) for i in (1,2,3)])
print(result) # Aug 7 14:23
Or:
l=['root pts/3 100.121.17.73 Tue Aug 7 14:22 - 14:23 (00:00) ']
print(' '.join(l[0].split()[-6:][:-1]))
Output:
Aug 7 14:22 - 14:23
I have a function which is supposed to build a header for a calendar like so:
' Sun Mon Tue Wed Thu Fri Sat '
It takes a isoweekday (one of '#Monday' 1, 2, 3, 4, 5, 6, 7 '#Sunday').
Here is the code:
#staticmethod
def _isoweekday_to_str(isoweekday):
isoweekday = isoweekday - 1
isoweekday = str(isoweekday)
x = datetime.strptime(isoweekday, '%w')
return x.strftime('%a')
TEXT_CAL_MONTH_WEEK_HEADER = ""
iter_isoweekday = week_start
for _ in range(0,7):
TEXT_CAL_MONTH_WEEK_HEADER += self._isoweekday_to_str(iter_isoweekday).rjust(TEXT_CAL_CELL_WIDTH, " ")
if iter_isoweekday != 7:
iter_isoweekday += 1
else:
iter_isoweekday = 1
The output I'm getting, when passing in 4 as the week start, is:
' Mon Mon Mon Mon Mon Mon Mon '
it should be:
' Thu Fri Sat Sun Mon Tue Wed '
I'm really, really not sure what's going on. I think it's either something to do with the way variables are assigned, string mutation, or the datetime library.
UPDATE: it appears that datetime.strptime is the problem. No matter what I pass in, I get datetime(1900, 1, 1, 0, 0) back... which, you guessed it, was a Monday.
Help?
You can get the localised days of the week from the calendar module:
>>> import calendar
>>> list(calendar.day_name)
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
Or the abbreviated names, using calendar.day_abbr:
>>> ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
See the documentation if you need other locales.
Obviously, the module can produce whole calendars:
>>> print calendar.TextCalendar().formatmonth(2016, 1)
January 2016
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
I'm not sure why you want to do it this way, but you need an actual date to pass to strptime rather than an isoweekday. For example,
from datetime import datetime
TEXT_CAL_CELL_WIDTH = 5
def _isoweekday_to_str(isoweekday):
isoweekday = '1900-01-{:02d}'.format(isoweekday)
x = datetime.strptime(isoweekday, '%Y-%m-%d')
return x.strftime('%a')
TEXT_CAL_MONTH_WEEK_HEADER = ""
week_start = 4
iter_isoweekday = week_start
for _ in range(0,7):
TEXT_CAL_MONTH_WEEK_HEADER += _isoweekday_to_str(iter_isoweekday).rjust(TEXT_CAL_CELL_WIDTH, " ")
if iter_isoweekday != 7:
iter_isoweekday += 1
else:
iter_isoweekday = 1
print(TEXT_CAL_MONTH_WEEK_HEADER )
Output:
Thu Fri Sat Sun Mon Tue Wed
(This works because 01/01/1900 was a Monday).
But why not do something similar with a dictionary of day names:
day_names = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
def weekday_header(week_start):
header = ''.join(['{:4s}'.format(day_names[(day_number+week_start) % 7])
for day_number in range(7)])
return header
print(weekday_header(4))
I have a dictionary of my calendar items for a month (date as "key", items in the form of a list as "value") that I want to print out a certain way (That dictionary in included in the code, assigned to dct). I only want to display items that are on or after the current date (i.e. today). The display format is:
day: item1, item2
I also want those items to span only 5 lines of stdout with each line 49 characters wide (spaces included). This is necessary because the output will be displayed in conky (app for linux).
Since a day can have multiple agenda items, the output will have to be wrapped and printed out on more than one line. I want the code to account for that by selecting only those days whose items can fit in 5 or less lines instead of printing 5 days with associated items on >5 lines. For e.g.
day1: item1, item2
item3
day2: item1
day3: item1,
item2
Thats 3 days on/after current day printing on 5 lines with each line 49 char wide. Strings exceeding 49 char are wrapped on newline.
Here is the code i've written to do this:
#!/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))
The result is:
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
I've commented the code heavily so it shouldn't be difficult to figure out how it works. I'm basically calculating the days farthest away from current day using datetime and skipping those days and their items. The code usually works well but once in a while it doesn't. In this case the output should have been:
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
since these are the days after the current day (Fri 16 Aug) whose items fit in 5 lines. How do I fix it to skip n no of lines rather than no of days farthest away from today?
I was thinking of using key_len dict to somehow filter the output further, by printing the items of only those days whose items length sum up to < or = 5...
I'm stuck.
It's very hard to tell what you're asking here, and your code is a huge muddle.
However, the reason you're getting the wrong output in the given example is very obvious, and matches the TODO comment in your code, so I'm going to assume that's the only part you're asking about:
# TODO: 'n' no of event lines should be skipped, NOT n no of days!
I don't understand why you want to skip to the last 5 lines after today instead of the first 5, but I'll assume you have some good reason for that.
The easiest way to solve this is to just do them in reverse, prepend the lines to a string instead of printing them directly, stop when you've reached 5 lines, and then print the string. (This would also save the wasteful re-building of the heap over and over, etc.)
For example, something like this:
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)
There are a lot of ways you could simplify this. For example, instead of passing around string representations of dates and using parse_date all over the place, just pass around dates, and format them once at the end. Use string formatting instead of 120-character multiple-concatenation expressions. Build your data structures once and use them, instead of rebuilding them over and over where you need them. And so on. But this should be all you need to get it to work.
Re-phrasing my Question, as suggested by moderator.
I need to create a calendar with Python & CSS for a web page, I tried the following in Python:
#!/usr/bin/env python
import os, re, sys, calendar
from datetime import datetime
myCal = calendar.monthcalendar(2011,9)
html += str(myCal)
mycal = myCal[:1]
cal1 = myCal[1:2]
cal2 = myCal[2:3]
cal3 = myCal[3:4]
cal4 = myCal[4:5]
html += str(mycal)+'<br>'
html += str(cal1)+'<br>'
html += str(cal2)+'<br>'
html += str(cal3)+'<br>'
html += str(cal4)+'<br>'
html += "<br>"
This is the following output on the web page:
[[0, 0, 0, 1, 2, 3, 4]]<br>
[[5, 6, 7, 8, 9, 10, 11]]<br>
[[12, 13, 14, 15, 16, 17, 18]]<br>
[[19, 20, 21, 22, 23, 24, 25]]<br>
[[26, 27, 28, 29, 30, 0, 0]]<br>
How can I arrange the above in the following format below?
(
This is a SAMPLE format, I have not done the actual Day / Date match.
The format needs to be in TWO rows.
eg.DayDateimgNDayDateimgN next month
)
Dec , 2011
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....
Jan , 2012
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....
Feb , 2012
----------------------------------------------------------------------------
sun | mon | tue | wed thu fri sat sun mon tue wed thu fri sat sun
-------|-------|-------|----------------------------------------------------
.... 1 |.. 2 ..|.. 3 ..| 4 5 6 7 8 9 10 11 12 13 14 15<br>
------ |-------|-------|----------------------------------------------------
img1 | img2 | img3 | ....
I'm not sure exactly what you are looking for, this produces a table with the 3 rows you describe, but for the entire month (not just the first 15 days). I may be starting point
import calendar
import itertools
blank = " "
myCal = calendar.monthcalendar(2011,9)
day_names = itertools.cycle(['mon','tue','wed','thu','fri','sat','sun']) # endless list
cal = [day for week in myCal for day in week] # flatten list of lists
# empty lists to hold the data
headers = []
numbers = []
imgs = []
# fill lists
for d in cal:
if d != 0:
headers.append(day_names.next())
numbers.append(d)
imgs.append("image"+str(d))
else:
headers.append(day_names.next())
numbers.append(blank)
imgs.append(blank)
# format data
html = "<table><tr></tr>{0}<tr>{1}</tr><tr>{2}</tr></table>".format(
"".join(["<td>%s</td>"% h for h in headers]),
"".join(["<td>%s</td>"% n for n in numbers]),
"".join(["<td>%s</td>"% i for i in imgs]))
I'm not quiet sure I understand the exact format your wanting but you can put the calender into a table of 3 rows.
Try this for each of your months
import calendar
myCal = calendar.monthcalendar(2011,9)
#make multi rowed month into a single row list
days = list()
for x in myCal:
days.extend(x)
#match this up with the week names with enough weeks to cover the month
weeks = len(myCal) * ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
#some images
images = ['image1', 'image2', '...']
#make sure there is at least a zero at the end of the list
days.append(0)
#find start and end indexes where the actual day numbers lie
start_index = days.index(1)
#if there are no zeros at the end of the list this will fail
end_index = days[start_index:].index(0) + len(days) - len(days[start_index:])
header = 'Dec, 2011'
#Create the table rows of just the items between start_index and end_index.
weekday_row = '<tr>%s</tr>'%(''.join(['<td>%s</td>'%(x)
for x in weeks[start_index:end_index]]))
day_row = '<tr>%s</tr>'%(''.join(['<td>%d</td>'%(x)
for x in days[start_index:end_index]]))
image_row = '<tr>%s</tr>'%(''.join(['<td>%s</td>' % (x) for x in images]))
#finally put them all together to form your month block
html = '<div>%s</div><table>\n\n%s\n\n%s\n\n%s</table>' % (header,
weekday_row,
day_row,
image_row)
You can repeat that as many times as you need