My bot reads another bot's message, then temporarily saves that message, makes a few changes with .replace and then the bot is supposed to change the format of the entries it finds.
I have tried quite a few things, but have not figured it out.
The text looks like this:
06 6 452872995438985XXX
09 22 160462182344032XXX
11 17 302885091519234XXX
And I want to get the following format:
6/06 452872995438985XXX
22/09 160462182344032XXX
17/11 302885091519234XXX
I have already tried the following things:
splitsprint = test.split(' ') # test is in this case the string we use e.g. the text shown above
for x in splitsprint:
month, day, misc = x
print(f"{day}/{month} {misc}")
---
newline = test.split('\n')
for line in newline:
month, day, misc = line.split(' ')
print(f"{day}/{month} {misc}")
But always I got a ValueError: too many values to unpack (expected 3) error or similar.
Does anyone here see my error?
It's because of the trailing white space in the input, I'm guessing. Use strip
s = '''
06 6 452872995438985XXX
09 22 160462182344032XXX
11 17 302885091519234XXX
'''
lines = s.strip().split('\n')
tokens = [l.split(' ') for l in lines]
final = [f'{day}/{month} {misc}' for month, day, misc in tokens]
for f in final:
print(f)
I'm new to Python & here is my question
Write a program to read through the mbox-short.txt and figure out the distribution by hour of the day for each of the messages. You can pull the hour out from the 'From ' line by finding the time and then splitting the string a second time using a colon.
From stephen.marquard#uct.ac.za Sat Jan 5 09:14:16 2008
Once you have accumulated the counts for each hour, print out the counts, sorted by hour as shown below.
Link of the file:
http://www.pythonlearn.com/code/mbox-short.txt
This is my code:
name = raw_input("Enter file:")
if len(name) < 1 : name = "mbox-short.txt"
handle = open(name)
counts = dict()
for line in handle:
if not line.startswith ("From "):continue
#words = line.split()
col = line.find(':')
coll = col - 2
print coll
#zero = line.find('0')
#one = line.find('1')
#b = line[ zero or one : col ]
#print b
#hour = words[5:6]
#print hour
#for line in hour:
# hr = line.split(':')
# x = hr[1]
for x in coll:
counts[x] = counts.get(x,0) + 1
for key, value in sorted(counts.items()):
print key, value
My first try was with list splitting(Comments) and it didn't work as it considered the 0 & the 1 as the first & the second letter not the numbers
second one was with line find (:) which is partially worked with minutes not with hours as required!!
First question
Why when I write line.find(:), it takes automatically the 2 numbers after?
Second question
Why when I run the program now, it gives an error
TypeError: 'int' object is not iterable on line 26 ??
Third question
Why it considered 0 & 1 as first & second letters of the line not 0 & 1 numbers
Finally
If possible please solve me this problem with a little of explanation please (with the same codes to keep my learning sequence)
Thank you...
First question
Why when I write line.find(:), it takes automatically the 2 numbers
after?
str.find() return the first index of the character that you want to find. If your string is "From 00:00:00", it returns 7 as the first ':' is at index 7.
Second question
Why when I run the program now, it gives an error TypeError: 'int'
object is not iterable on line 26 ??
As have said above, it returns an int, which you cannot iterate
Third question
Why it considered 0 & 1 as first & second letters of the line not 0 &
1 numbers
I don't really understand what do you mean here. Anyway, as I understand, you try to find the first index which '0' or '1' occurs and assume that the first letter of hour? What about 8-11pm(start with 2)?
Finally If possible please solve me this problem with a little of
explanation please (with the same codes to keep my learning sequence)
Sure, it will be like this:
for line in f:
if not line.startswith("From "): continue
first_colon_index = line.find(":")
if first_colon_index == -1: # there is no ':'
continue
first_char_hour_index = first_colon_index - 2
# string slicing
# [a:b] get string from index a to b
hour = line[first_char_hour_index:first_char_hour_index+2]
hour_int = int(hour)
# if key exist, increase by 1. If not, set to 1
if hour_int in count:
count[hour_int] += 1
else:
count[hour_int] = 1
# print hour & count, in sorting order
for hour in sorted(count):
print hour, count[hour]
The part about string slicing can be confusing, you can read more about it at Python docs.
And you have to sure that: in the line, there is no other ":" or this method will fail as the first ":" will not be the one between hour and minute.
To make sure it works, it's better to use Regex. Something like:
for line in f:
if not line.startswith("From"): continue
match = re.search(r'^From.*?([0-9]{2,2}:[0-9]{2,2}:[0-9]{2,2})', line)
if match:
time = match.group(1) # hh:mm:ss
hh = int(time.split(":")[0])
# if key exist, increase by 1. If not, set to 1
if hh in count:
count[hh] += 1
else:
count[hh] = 1
# print hour & count, in sorting order
for hour in sorted(count):
print hour, count[hour]
That's because str.find() returns an index of the found substring, not the string itself. Consequently, when you subtract 2 from it and then try to loop through it it will complain that you're trying to loop through an integer and raise a TypeError.
You can grab the whole time string as:
time_start = line.find(":")
if time_start == -1: # not found
continue
time_string = line[time_start-2:time_start+6] # slice out the whole time string
You can then further split the time_string by : to get hours, minutes and seconds (e.g. hours, minutes, seconds = time_string.split(":", 2) just keep in mind that those will be strings, not integers), or if you just want the hour:
hour = int(line[time_start-2:time_start])
You can take it from there - just increase your dict value and when you're done with parsing the file sort everything out.
I m using Python in Raspberry Pi and my packet is in hexadecimal value like "0x750x010x010x060x000x08". I want serial communication between UART and Raspberry Pi so I wrote a program using Python in Raspberry Pi and I'm checking data on terminal but when I selected ASCII option in terminal it showing below output:
75
01
01
06
00
08
And when I selected hex option in terminal it is not showing above output. Now I want above output when I will select hex option but not ASCII option. So how to get that? If I need to convert it into hex or byte or any other than tell me the code in Python.
import serial
port=serial.Serial("/dev/ttyAMA0",baudrate=115200,timeout=3.0)
while True:
a="0x750x010x010x060x000x08"
b=a.replace("0x"," ")
#print b
alist = b.split(" ")
for element in alist
port.write("\r\n"+str(element))
this gives the desired formatted data you want
First of all your for loop and if statment are used wrong here, and they are not required. The while loop can be equivently rewriten as:
a = "0x750x010x010x060x000x08"
b = a.replace("0x", " ")
while True:
port.write("\r\n"+b)
Your main misanderstanding is that you assume Python understands you want to iterate over hex numbers. But it doesn't. In you original loop it just iterates the a string letter by letter. And in fact at each iteration of for loop you just changes the orignal a string to " 75 01 01 06 00 08" and send it as a string.
If you need to send bytes, you should split your string into separate records with each byte's infromation and convert these records to bytes.
Here is the code for that
a = "0x750x010x010x060x000x08"
b1 = a.split("0x")
# b1 is ["", "75", "01", "01", "06", "00", "08"], the values are still strings
b2 = [int(x, 16) for x in b1[1:]]
# b2 is a list of integers, the values calculated from strings assuming they are hex (16-bit) numbers
# use b1[1:] to cut the first blank string
b = str(bytearray(b2))
#b joins values list into a bytes string (each interger transformed into one byte)
while True:
port.write("\r\n" + b)
Update for question in comments:
If a format is like this "0x750101060008", you just split it by 2 letters:
b1 = [a[2*i:2*i+2] for i in range(len(a)/2)]
import serial
port=serial.Serial("/dev/ttyAMA0",baudrate=115200,timeout=3.0)
while True:
a="0x750x010x010x060x000x08"
b=a.replace("0x"," ")
#print b
alist = b.split(" ")
for element in alist
port.write("\r\n"+str(element))
this one
I am writing a code where I want to search term "X-DSPAM-Confidence: 0.8475" from mbox.text file. well so far, I can search the string and count the number of times it appears in the file. Now the problem is, I have to add the end digits of that string ( here- 0.8475 ) every time it appears in the text file. I need help because I stuck there and couldn't count the total of the float number appears at the end of that string.
The content of my file looks like this:
X-Content-Type-Message-Body: text/plain; charset=UTF-8
Content-Type: text/plain; charset=UTF-8
X-DSPAM-Result: Innocent
X-DSPAM-Processed: Sat Jan 5 09:14:16 2008
X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000
My code:
text_file = raw_input ("please enter the path of the file that you want to open:")
open_file = open ( text_file )
print "Text file has been open "
count = 0
total = 0.00000
for line in open_file:
if 'X-DSPAM-Confidence:' in line:
total =+ float(line[20:])
count = count + 1
print total/count
print "The number of line with X-DSPAM-Confidence: is:", count
How can I do that?
slicing returns a list not a value and the in-place operator for addition is += not =+. That being said you should use split.
total = 0.00000
for line in open_file:
if 'X-DSPAM-Confidence:' in line:
total += float(line.split()[-1]) # change here.
count = count + 1
print total/count
Or even better using sum and len.
with open('test.txt') as f:
data = [float(line.split()[-1]) for line in f if line.strip().startswith('X-DSPAM-Confidence:')]
print(sum(data)/len(data))
Python 3.4 or newer solution using mean from the statistics module.
from statistics import mean
with open('test.txt') as f:
data = [float(line.split()[-1]) for line in f if line.strip().startswith('X-DSPAM-Confidence:')]
print(mean(data))
The print statement, much like a magic 8-Ball, tells all
>>> print repr(line[20:])
' 0.0000\n'
You simply bit off more than float could choose. Narrow it down a bit
total += float(line[21:-1])
I am trying to get my output data to look like this:
-------------------------------------------------------
Grade Report for Programs
-------------------------------------------------------
Jacobson, Mark 19.0 <--- 20,17,20
Snurd, Mortimur 16.5 <--- 20,19,18,17,16,15,14,13
Luxemburg, Rosa 15.0 <--- 18,15,20,10,12
Atanasoff, John 20.0 <--- 20,20,20,20,20,20,20
Hopper, Grace 20.0 <--- 20,20,20,20,20,20
-------------------------------------------------------
But I don't know how to deal with the varying name length. My output currently looks like this.
Grade Report for Programs
-------------------------------------------------------
Jacobson, Mark 19.0 <--- 20,17,20
Snurd, Mortimur 16.5 <--- 20,19,18,17,16,15,14,13
Luxemburg, Rosa 15.0 <--- 18,15,20,10,12
Atanasoff, John 20.0 <--- 20,20,20,20,20,20,20
Hopper, Grace 20.0 <--- 20,20,20,20,20,20
-------------------------------------------------------
The program I have written is to take an input file of grade scores and collect the data and neatly print out the average.
The input file looks something like this:
Mark Jacobson,20,17,20
Mortimur Snurd,20,19,18,17,16,15,14,13
Rosa Luxemburg,18,15,20,10,12
John Atanasoff,20,20,20,20,20,20,20
Grace Hopper,20,20,20,20,20,20
And here is my code that collects the name and scores, and prints out the data with last name, first name, average score, then the actual scores that resulted to the average.
file = input("Enter filename: ")
grade_file = open(file, 'r')
print()
print('---------------------------------------------------------')
print('\t\tGrade Report for Programs')
print('---------------------------------------------------------')
for text in grade_file:
end_of_name = text.find(',')
name_seperated = text.find(' ')
first_name = text[0:name_seperated]
last_name = text[name_seperated+1:end_of_name]
name_last_first = last_name + "," + " " + first_name
grades = text[end_of_name+1:]
start = 0
index = 0
sum_n = 0
average= 0
score = 0
count = 0
while index < len(grades):
if grades[index] == ',':
score = int(grades[start:index])
count += 1
sum_n = score + sum_n
start = index + 1
index += 1
count += 1
score = int(grades[start:index])
sum_n = score + sum_n
average = sum_n / count
print(name_last_first, " ", average, "<---", grades)
print('---------------------------------------------------------')
grade_file.close()
I just need to figure out how to have even spaces so it makes an even row and column like the first output. Help is greatly appreciated! Thanks!
One way is to use Python's builtin C-style formatting. Note that a negative field width indicates that the field is to be left-justified:
>>> print("%-30s %4.1f" % ("Jacobson, Mark", 19.0))
Jacobson, Mark 19.0
>>>
Alternatively, you can use the string format method:
>>> print("{:30s} {:4.1f}".format("Jacobson, Mark", 19.0))
Jacobson, Mark 19.0
>>>
You can also use Formatted String Literals (f-strings):
>>> name = "Jacobson, Mark"
>>> average = 19.0
>>> print(f"{name:30s} {average:4.1f}")
Jacobson, Mark 19.0
>>>
Use string formatting with field width specifiers:
print('{:20s} {:4.1f} <--- {}'.format(name_last_first, average, grades))
This uses the str.format() method with the Format String Syntax to slot values into a template.
The first slot formats strings into a field 20 characters wide, the second slots floating point numbers into a field 4 characters wide, using 1 digit after the decimal point (leaving 1 for the decimal point itself plus 2 digits before the point).
If I were you, I'd also look at the csv module to read your data, rather than use string manipulations. You'll get list objects with separate values for each column:
import csv
print('---------------------------------------------------------')
print('\t\tGrade Report for Programs')
print('---------------------------------------------------------')
with open(file, 'r', newline='') as grade_file:
reader = csv.reader(grade_file)
for row in reader:
name = row[0]
name = ' '.join(map(str.strip, reversed(name.split(',')))
grades = [int(g) for g in row[1:])
average = sum(grades) / len(grades)
print('{:20s} {:4.1f} <--- {}'.format(name, average, ','.join(grades)))
print('---------------------------------------------------------')
The answer I find easiest is just using some basic string arithmetic.
For example, say for want the aligned a variable 20 spaces ahead of left-alignment, in your case the "average" variable, you could simply do this
print(name_last_first + (' ' * (20-len(name_last_first))) + average
+ "<----" + grades)
It's just a bit lengthier, but the code is easier to interpret in my opinion.
(Note: this method only works with mono spaced fonts! But most Python output is defaulted to a MS font :-) )
You can use this code :
handle = open('grade.txt')
name= list()
avg = list()
scores = list()
for line in handle:
line = line.strip()
spos = line.find(',')
scores.append(line[spos+1:])
words = line.split(',')
words = words
name.append(words[0])
add = 0
for i in range(1,len(words)):
add = add+int(words[i])
average = add/(len(words)-1)
avg.append(average)
for i in range(len(avg)):
tname = name[i].split()
fname = tname[0]
sname = tname[1]
order = sname+', '+fname
print("%-20s %-3.1f <--- %-30s " %(order,float(avg[i]),scores[i]))
The final line is for displaying it in an organized manner, you're code was lacking it only.